Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 42689ea

Browse files
authored
Sped up FlutterStandardCodec writing speed. (#38345)
* Sped up FlutterStandardCodec writing speed. * added clear division of reader and writer helpers * updated doxygen comment
1 parent 60cf34e commit 42689ea

File tree

3 files changed

+250
-82
lines changed

3 files changed

+250
-82
lines changed

shell/platform/darwin/common/framework/Source/FlutterStandardCodec.mm

+112-82
Original file line numberDiff line numberDiff line change
@@ -211,114 +211,144 @@ - (instancetype)initWithData:(NSMutableData*)data {
211211
}
212212

213213
- (void)writeByte:(UInt8)value {
214-
[_data appendBytes:&value length:1];
214+
FlutterStandardCodecHelperWriteByte((__bridge CFMutableDataRef)_data, value);
215215
}
216216

217217
- (void)writeBytes:(const void*)bytes length:(NSUInteger)length {
218-
[_data appendBytes:bytes length:length];
218+
FlutterStandardCodecHelperWriteBytes((__bridge CFMutableDataRef)_data, bytes, length);
219219
}
220220

221221
- (void)writeData:(NSData*)data {
222-
[_data appendData:data];
222+
FlutterStandardCodecHelperWriteData((__bridge CFMutableDataRef)_data, (__bridge CFDataRef)data);
223223
}
224224

225225
- (void)writeSize:(UInt32)size {
226-
if (size < 254) {
227-
[self writeByte:(UInt8)size];
228-
} else if (size <= 0xffff) {
229-
[self writeByte:254];
230-
UInt16 value = (UInt16)size;
231-
[self writeBytes:&value length:2];
232-
} else {
233-
[self writeByte:255];
234-
[self writeBytes:&size length:4];
235-
}
226+
FlutterStandardCodecHelperWriteSize((__bridge CFMutableDataRef)_data, size);
236227
}
237228

238229
- (void)writeAlignment:(UInt8)alignment {
239-
UInt8 mod = _data.length % alignment;
240-
if (mod) {
241-
for (int i = 0; i < (alignment - mod); i++) {
242-
[self writeByte:0];
243-
}
244-
}
230+
FlutterStandardCodecHelperWriteAlignment((__bridge CFMutableDataRef)_data, alignment);
245231
}
246232

247233
- (void)writeUTF8:(NSString*)value {
248-
UInt32 length = [value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
249-
[self writeSize:length];
250-
[self writeBytes:value.UTF8String length:length];
234+
FlutterStandardCodecHelperWriteUTF8((__bridge CFMutableDataRef)_data,
235+
(__bridge CFStringRef)value);
251236
}
252237

253-
- (void)writeValue:(id)value {
254-
if (value == nil || value == [NSNull null]) {
255-
[self writeByte:FlutterStandardFieldNil];
238+
static FlutterStandardCodecObjcType GetWriteType(id value) {
239+
if (value == nil || (__bridge CFNullRef)value == kCFNull) {
240+
return FlutterStandardCodecObjcTypeNil;
256241
} else if ([value isKindOfClass:[NSNumber class]]) {
257-
CFNumberRef number = (__bridge CFNumberRef)value;
258-
BOOL success = NO;
259-
if (CFGetTypeID(number) == CFBooleanGetTypeID()) {
260-
BOOL b = CFBooleanGetValue((CFBooleanRef)number);
261-
[self writeByte:(b ? FlutterStandardFieldTrue : FlutterStandardFieldFalse)];
262-
success = YES;
263-
} else if (CFNumberIsFloatType(number)) {
264-
Float64 f;
265-
success = CFNumberGetValue(number, kCFNumberFloat64Type, &f);
266-
if (success) {
267-
[self writeByte:FlutterStandardFieldFloat64];
268-
[self writeAlignment:8];
269-
[self writeBytes:(UInt8*)&f length:8];
270-
}
271-
} else if (CFNumberGetByteSize(number) <= 4) {
272-
SInt32 n;
273-
success = CFNumberGetValue(number, kCFNumberSInt32Type, &n);
274-
if (success) {
275-
[self writeByte:FlutterStandardFieldInt32];
276-
[self writeBytes:(UInt8*)&n length:4];
277-
}
278-
} else if (CFNumberGetByteSize(number) <= 8) {
279-
SInt64 n;
280-
success = CFNumberGetValue(number, kCFNumberSInt64Type, &n);
281-
if (success) {
282-
[self writeByte:FlutterStandardFieldInt64];
283-
[self writeBytes:(UInt8*)&n length:8];
284-
}
285-
}
286-
if (!success) {
287-
NSLog(@"Unsupported value: %@ of number type %ld", value, CFNumberGetType(number));
288-
NSAssert(NO, @"Unsupported value for standard codec");
289-
}
242+
return FlutterStandardCodecObjcTypeNSNumber;
290243
} else if ([value isKindOfClass:[NSString class]]) {
291-
NSString* string = value;
292-
[self writeByte:FlutterStandardFieldString];
293-
[self writeUTF8:string];
244+
return FlutterStandardCodecObjcTypeNSString;
294245
} else if ([value isKindOfClass:[FlutterStandardTypedData class]]) {
295-
FlutterStandardTypedData* typedData = value;
296-
[self writeByte:FlutterStandardFieldForDataType(typedData.type)];
297-
[self writeSize:typedData.elementCount];
298-
[self writeAlignment:typedData.elementSize];
299-
[self writeData:typedData.data];
246+
return FlutterStandardCodecObjcTypeFlutterStandardTypedData;
300247
} else if ([value isKindOfClass:[NSData class]]) {
301-
[self writeValue:[FlutterStandardTypedData typedDataWithBytes:value]];
248+
return FlutterStandardCodecObjcTypeNSData;
302249
} else if ([value isKindOfClass:[NSArray class]]) {
303-
NSArray* array = value;
304-
[self writeByte:FlutterStandardFieldList];
305-
[self writeSize:array.count];
306-
for (id object in array) {
307-
[self writeValue:object];
308-
}
250+
return FlutterStandardCodecObjcTypeNSArray;
309251
} else if ([value isKindOfClass:[NSDictionary class]]) {
310-
NSDictionary* dict = value;
311-
[self writeByte:FlutterStandardFieldMap];
312-
[self writeSize:dict.count];
313-
for (id key in dict) {
314-
[self writeValue:key];
315-
[self writeValue:[dict objectForKey:key]];
316-
}
252+
return FlutterStandardCodecObjcTypeNSDictionary;
317253
} else {
318-
NSLog(@"Unsupported value: %@ of type %@", value, [value class]);
319-
NSAssert(NO, @"Unsupported value for standard codec");
254+
return FlutterStandardCodecObjcTypeUnknown;
320255
}
321256
}
257+
258+
struct WriteKeyValuesInfo {
259+
CFTypeRef writer;
260+
CFMutableDataRef data;
261+
};
262+
263+
static void WriteKeyValues(CFTypeRef key, CFTypeRef value, void* context) {
264+
WriteKeyValuesInfo* info = (WriteKeyValuesInfo*)context;
265+
FastWriteValueOfType(info->writer, info->data, key);
266+
FastWriteValueOfType(info->writer, info->data, value);
267+
}
268+
269+
// Recurses into WriteValueOfType directly if it is writing a known type,
270+
// otherwise recurses with objc_msgSend.
271+
static void FastWriteValueOfType(CFTypeRef writer, CFMutableDataRef data, CFTypeRef value) {
272+
FlutterStandardCodecObjcType type = GetWriteType((__bridge id)value);
273+
if (type != FlutterStandardCodecObjcTypeUnknown) {
274+
WriteValueOfType(writer, data, type, value);
275+
} else {
276+
[(__bridge FlutterStandardWriter*)writer writeValue:(__bridge id)value];
277+
}
278+
}
279+
280+
static void WriteValueOfType(CFTypeRef writer,
281+
CFMutableDataRef data,
282+
FlutterStandardCodecObjcType type,
283+
CFTypeRef value) {
284+
switch (type) {
285+
case FlutterStandardCodecObjcTypeNil:
286+
FlutterStandardCodecHelperWriteByte(data, FlutterStandardFieldNil);
287+
break;
288+
case FlutterStandardCodecObjcTypeNSNumber: {
289+
CFNumberRef number = (CFNumberRef)value;
290+
BOOL success = FlutterStandardCodecHelperWriteNumber(data, number);
291+
if (!success) {
292+
NSLog(@"Unsupported value: %@ of number type %ld", value, CFNumberGetType(number));
293+
NSCAssert(NO, @"Unsupported value for standard codec");
294+
}
295+
break;
296+
}
297+
case FlutterStandardCodecObjcTypeNSString: {
298+
CFStringRef string = (CFStringRef)value;
299+
FlutterStandardCodecHelperWriteByte(data, FlutterStandardFieldString);
300+
FlutterStandardCodecHelperWriteUTF8(data, string);
301+
break;
302+
}
303+
case FlutterStandardCodecObjcTypeFlutterStandardTypedData: {
304+
FlutterStandardTypedData* typedData = (__bridge FlutterStandardTypedData*)value;
305+
FlutterStandardCodecHelperWriteByte(data, FlutterStandardFieldForDataType(typedData.type));
306+
FlutterStandardCodecHelperWriteSize(data, typedData.elementCount);
307+
FlutterStandardCodecHelperWriteAlignment(data, typedData.elementSize);
308+
FlutterStandardCodecHelperWriteData(data, (__bridge CFDataRef)typedData.data);
309+
break;
310+
}
311+
case FlutterStandardCodecObjcTypeNSData:
312+
WriteValueOfType(writer, data, FlutterStandardCodecObjcTypeFlutterStandardTypedData,
313+
(__bridge CFTypeRef)
314+
[FlutterStandardTypedData typedDataWithBytes:(__bridge NSData*)value]);
315+
break;
316+
case FlutterStandardCodecObjcTypeNSArray: {
317+
CFArrayRef array = (CFArrayRef)value;
318+
FlutterStandardCodecHelperWriteByte(data, FlutterStandardFieldList);
319+
CFIndex count = CFArrayGetCount(array);
320+
FlutterStandardCodecHelperWriteSize(data, count);
321+
for (CFIndex i = 0; i < count; ++i) {
322+
FastWriteValueOfType(writer, data, CFArrayGetValueAtIndex(array, i));
323+
}
324+
break;
325+
}
326+
case FlutterStandardCodecObjcTypeNSDictionary: {
327+
CFDictionaryRef dict = (CFDictionaryRef)value;
328+
FlutterStandardCodecHelperWriteByte(data, FlutterStandardFieldMap);
329+
CFIndex count = CFDictionaryGetCount(dict);
330+
FlutterStandardCodecHelperWriteSize(data, count);
331+
WriteKeyValuesInfo info = {
332+
.writer = writer,
333+
.data = data,
334+
};
335+
CFDictionaryApplyFunction(dict, WriteKeyValues, (void*)&info);
336+
break;
337+
}
338+
case FlutterStandardCodecObjcTypeUnknown: {
339+
id objc_value = (__bridge id)value;
340+
NSLog(@"Unsupported value: %@ of type %@", objc_value, [objc_value class]);
341+
NSCAssert(NO, @"Unsupported value for standard codec");
342+
break;
343+
}
344+
}
345+
}
346+
347+
- (void)writeValue:(id)value {
348+
FlutterStandardCodecObjcType type = GetWriteType(value);
349+
WriteValueOfType((__bridge CFTypeRef)self, (__bridge CFMutableDataRef)self->_data, type,
350+
(__bridge CFTypeRef)value);
351+
}
322352
@end
323353

324354
@implementation FlutterStandardReader {

shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.c

+95
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,98 @@ CFTypeRef FlutterStandardCodecHelperReadValueOfType(
164164
assert(false);
165165
}
166166
}
167+
168+
void FlutterStandardCodecHelperWriteByte(CFMutableDataRef data, uint8_t value) {
169+
CFDataAppendBytes(data, &value, 1);
170+
}
171+
172+
void FlutterStandardCodecHelperWriteBytes(CFMutableDataRef data,
173+
const void* bytes,
174+
unsigned long length) {
175+
CFDataAppendBytes(data, bytes, length);
176+
}
177+
178+
void FlutterStandardCodecHelperWriteSize(CFMutableDataRef data, uint32_t size) {
179+
if (size < 254) {
180+
FlutterStandardCodecHelperWriteByte(data, size);
181+
} else if (size <= 0xffff) {
182+
FlutterStandardCodecHelperWriteByte(data, 254);
183+
UInt16 value = (UInt16)size;
184+
FlutterStandardCodecHelperWriteBytes(data, &value, 2);
185+
} else {
186+
FlutterStandardCodecHelperWriteByte(data, 255);
187+
FlutterStandardCodecHelperWriteBytes(data, &size, 4);
188+
}
189+
}
190+
191+
void FlutterStandardCodecHelperWriteAlignment(CFMutableDataRef data,
192+
uint8_t alignment) {
193+
uint8_t mod = CFDataGetLength(data) % alignment;
194+
if (mod) {
195+
for (int i = 0; i < (alignment - mod); i++) {
196+
FlutterStandardCodecHelperWriteByte(data, 0);
197+
}
198+
}
199+
}
200+
201+
void FlutterStandardCodecHelperWriteUTF8(CFMutableDataRef data,
202+
CFStringRef value) {
203+
const char* utf8 = CFStringGetCStringPtr(value, kCFStringEncodingUTF8);
204+
if (utf8) {
205+
size_t length = strlen(utf8);
206+
FlutterStandardCodecHelperWriteSize(data, length);
207+
FlutterStandardCodecHelperWriteBytes(data, utf8, length);
208+
} else {
209+
CFIndex length = CFStringGetLength(value);
210+
CFIndex used_length = 0;
211+
// UTF16 length times 3 will fit all UTF8.
212+
CFIndex buffer_length = length * 3;
213+
UInt8* buffer = (UInt8*)malloc(buffer_length * sizeof(UInt8));
214+
CFStringGetBytes(value, CFRangeMake(0, length), kCFStringEncodingUTF8, 0,
215+
false, buffer, buffer_length, &used_length);
216+
FlutterStandardCodecHelperWriteSize(data, used_length);
217+
FlutterStandardCodecHelperWriteBytes(data, buffer, used_length);
218+
free(buffer);
219+
}
220+
}
221+
222+
void FlutterStandardCodecHelperWriteData(CFMutableDataRef data,
223+
CFDataRef value) {
224+
const UInt8* bytes = CFDataGetBytePtr(value);
225+
CFIndex length = CFDataGetLength(value);
226+
FlutterStandardCodecHelperWriteBytes(data, bytes, length);
227+
}
228+
229+
bool FlutterStandardCodecHelperWriteNumber(CFMutableDataRef data,
230+
CFNumberRef number) {
231+
bool success = false;
232+
if (CFGetTypeID(number) == CFBooleanGetTypeID()) {
233+
bool b = CFBooleanGetValue((CFBooleanRef)number);
234+
FlutterStandardCodecHelperWriteByte(
235+
data, (b ? FlutterStandardFieldTrue : FlutterStandardFieldFalse));
236+
success = true;
237+
} else if (CFNumberIsFloatType(number)) {
238+
Float64 f;
239+
success = CFNumberGetValue(number, kCFNumberFloat64Type, &f);
240+
if (success) {
241+
FlutterStandardCodecHelperWriteByte(data, FlutterStandardFieldFloat64);
242+
FlutterStandardCodecHelperWriteAlignment(data, 8);
243+
FlutterStandardCodecHelperWriteBytes(data, &f, 8);
244+
}
245+
} else if (CFNumberGetByteSize(number) <= 4) {
246+
SInt32 n;
247+
success = CFNumberGetValue(number, kCFNumberSInt32Type, &n);
248+
if (success) {
249+
FlutterStandardCodecHelperWriteByte(data, FlutterStandardFieldInt32);
250+
FlutterStandardCodecHelperWriteBytes(data, &n, 4);
251+
}
252+
} else if (CFNumberGetByteSize(number) <= 8) {
253+
SInt64 n;
254+
success = CFNumberGetValue(number, kCFNumberSInt64Type, &n);
255+
if (success) {
256+
FlutterStandardCodecHelperWriteByte(data, FlutterStandardFieldInt64);
257+
FlutterStandardCodecHelperWriteBytes(data, &n, 8);
258+
}
259+
}
260+
return success;
261+
}

shell/platform/darwin/common/framework/Source/FlutterStandardCodecHelper.h

+43
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ static inline bool FlutterStandardFieldIsStandardType(uint8_t field) {
3737
field >= FlutterStandardFieldNil;
3838
}
3939

40+
typedef enum {
41+
FlutterStandardCodecObjcTypeNil,
42+
FlutterStandardCodecObjcTypeNSNumber,
43+
FlutterStandardCodecObjcTypeNSString,
44+
FlutterStandardCodecObjcTypeFlutterStandardTypedData,
45+
FlutterStandardCodecObjcTypeNSData,
46+
FlutterStandardCodecObjcTypeNSArray,
47+
FlutterStandardCodecObjcTypeNSDictionary,
48+
FlutterStandardCodecObjcTypeUnknown,
49+
} FlutterStandardCodecObjcType;
50+
51+
///////////////////////////////////////////////////////////////////////////////
52+
///\name Reader Helpers
53+
///@{
54+
4055
void FlutterStandardCodecHelperReadAlignment(unsigned long* location,
4156
uint8_t alignment);
4257

@@ -62,6 +77,34 @@ CFTypeRef FlutterStandardCodecHelperReadValueOfType(
6277
CFTypeRef (*ReadTypedDataOfType)(FlutterStandardField, CFTypeRef),
6378
CFTypeRef user_data);
6479

80+
///@}
81+
82+
///////////////////////////////////////////////////////////////////////////////
83+
///\name Writer Helpers
84+
///@{
85+
86+
void FlutterStandardCodecHelperWriteByte(CFMutableDataRef data, uint8_t value);
87+
88+
void FlutterStandardCodecHelperWriteBytes(CFMutableDataRef data,
89+
const void* bytes,
90+
unsigned long length);
91+
92+
void FlutterStandardCodecHelperWriteSize(CFMutableDataRef data, uint32_t size);
93+
94+
void FlutterStandardCodecHelperWriteAlignment(CFMutableDataRef data,
95+
uint8_t alignment);
96+
97+
void FlutterStandardCodecHelperWriteUTF8(CFMutableDataRef data,
98+
CFStringRef value);
99+
100+
void FlutterStandardCodecHelperWriteData(CFMutableDataRef data,
101+
CFDataRef value);
102+
103+
bool FlutterStandardCodecHelperWriteNumber(CFMutableDataRef data,
104+
CFNumberRef number);
105+
106+
///@}
107+
65108
#if defined(__cplusplus)
66109
}
67110
#endif

0 commit comments

Comments
 (0)