From d846b0b059b4d867536b98aa29475a387aa09114 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Mon, 8 Jun 2015 16:24:57 -0400 Subject: Beta quality drop of Objective C Support. - Add more to the ObjC dir readme. - Merge the ExtensionField and ExtensionDescriptor to reduce overhead. - Fix an initialization race. - Clean up the Xcode schemes. - Remove the class/enum filter. - Remove some forced inline that were bloating things without proof of performance wins. - Rename some internal types to avoid conflicts with the well know types protos. - Drop the use of ApplyFunctions to the compiler/optimizer can do what it wants. - Better document some possible future improvements. - Add missing support for parsing repeated primitive fields in packed or unpacked forms. - Improve -hash. - Add *Count for repeated and map<> fields to avoid auto create when checking for them being set. --- objectivec/GPBDescriptor.m | 307 ++++++++++++++++++++++++++++++++------------- 1 file changed, 220 insertions(+), 87 deletions(-) (limited to 'objectivec/GPBDescriptor.m') diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m index b955018c..bae9187e 100644 --- a/objectivec/GPBDescriptor.m +++ b/objectivec/GPBDescriptor.m @@ -369,16 +369,26 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { GPBWireFormat format; if ((description->flags & GPBFieldMapKeyMask) != 0) { // Maps are repeated messages on the wire. - format = GPBWireFormatForType(GPBTypeMessage, NO); + format = GPBWireFormatForType(GPBDataTypeMessage, NO); } else { - format = GPBWireFormatForType(description->type, - description->flags & GPBFieldPacked); + format = GPBWireFormatForType(description->dataType, + ((description->flags & GPBFieldPacked) != 0)); } return GPBWireFormatMakeTag(description->number, format); } +uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { + GPBMessageFieldDescription *description = self->description_; + NSCAssert((description->flags & GPBFieldRepeated) != 0, + @"Only valid on repeated fields"); + GPBWireFormat format = + GPBWireFormatForType(description->dataType, + ((description->flags & GPBFieldPacked) == 0)); + return GPBWireFormatMakeTag(description->number, format); +} + @implementation GPBFieldDescriptor { - GPBValue defaultValue_; + GPBGenericValue defaultValue_; GPBFieldOptions *fieldOptions_; // Message ivars @@ -416,12 +426,66 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { getSel_ = sel_getUid(description->name); setSel_ = SelFromStrings("set", description->name, NULL, YES); + GPBDataType dataType = description->dataType; + BOOL isMessage = GPBDataTypeIsMessage(dataType); + BOOL isMapOrArray = GPBFieldIsMapOrArray(self); + + if (isMapOrArray) { + // map<>/repeated fields get a *Count property (inplace of a has*) to + // support checking if there are any entries without triggering + // autocreation. + hasOrCountSel_ = SelFromStrings(NULL, description->name, "_Count", NO); + } else { + // If there is a positive hasIndex, then: + // - All fields types for proto2 messages get has* selectors. + // - Only message fields for proto3 messages get has* selectors. + // Note: the positive check is to handle oneOfs, we can't check + // containingOneof_ because it isn't set until after initialization. + if ((description->hasIndex >= 0) && + (description->hasIndex != GPBNoHasBit) && + ((syntax != GPBFileSyntaxProto3) || isMessage)) { + hasOrCountSel_ = SelFromStrings("has", description->name, NULL, NO); + setHasSel_ = SelFromStrings("setHas", description->name, NULL, YES); + } + } + + // Extra type specific data. + if (isMessage) { + const char *className = description->dataTypeSpecific.className; + msgClass_ = objc_getClass(className); + NSAssert(msgClass_, @"Class %s not defined", className); + } else if (dataType == GPBDataTypeEnum) { + if ((description_->flags & GPBFieldHasEnumDescriptor) != 0) { + enumHandling_.enumDescriptor_ = + description->dataTypeSpecific.enumDescFunc(); + } else { + enumHandling_.enumVerifier_ = + description->dataTypeSpecific.enumVerifier; + } + } + + // Non map<>/repeated fields can have defaults. + if (!isMapOrArray) { + defaultValue_ = description->defaultValue; + if (dataType == GPBDataTypeBytes) { + // Data stored as a length prefixed (network byte order) c-string in + // descriptor structure. + const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData; + if (bytes) { + uint32_t length = *((uint32_t *)bytes); + length = ntohl(length); + bytes += sizeof(length); + defaultValue_.valueData = + [[NSData alloc] initWithBytes:bytes length:length]; + } + } + } + + // FieldOptions stored as a length prefixed (network byte order) c-escaped + // string in descriptor records. if (description->fieldOptions) { - // FieldOptions stored as a length prefixed c-escaped string in descriptor - // records. uint8_t *optionsBytes = (uint8_t *)description->fieldOptions; uint32_t optionsLength = *((uint32_t *)optionsBytes); - // The length is stored in network byte order. optionsLength = ntohl(optionsLength); if (optionsLength > 0) { optionsBytes += sizeof(optionsLength); @@ -434,69 +498,20 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { error:NULL] retain]; } } - - GPBType type = description->type; - BOOL isMessage = GPBTypeIsMessage(type); - if (isMessage) { - // No has* for repeated/map or something in a oneof (we can't check - // containingOneof_ because it isn't set until after initialization). - if ((description->hasIndex >= 0) && - (description->hasIndex != GPBNoHasBit)) { - hasSel_ = SelFromStrings("has", description->name, NULL, NO); - setHasSel_ = SelFromStrings("setHas", description->name, NULL, YES); - } - const char *className = description->typeSpecific.className; - msgClass_ = objc_getClass(className); - NSAssert1(msgClass_, @"Class %s not defined", className); - // The defaultValue_ is fetched directly in -defaultValue to avoid - // initialization order issues. - } else { - if (!GPBFieldIsMapOrArray(self)) { - defaultValue_ = description->defaultValue; - if (type == GPBTypeData) { - // Data stored as a length prefixed c-string in descriptor records. - const uint8_t *bytes = (const uint8_t *)defaultValue_.valueData; - if (bytes) { - uint32_t length = *((uint32_t *)bytes); - // The length is stored in network byte order. - length = ntohl(length); - bytes += sizeof(length); - defaultValue_.valueData = - [[NSData alloc] initWithBytes:bytes length:length]; - } - } - // No has* methods for proto3 or if our hasIndex is < 0 because it - // means the field is in a oneof (we can't check containingOneof_ - // because it isn't set until after initialization). - if ((syntax != GPBFileSyntaxProto3) && (description->hasIndex >= 0) && - (description->hasIndex != GPBNoHasBit)) { - hasSel_ = SelFromStrings("has", description->name, NULL, NO); - setHasSel_ = SelFromStrings("setHas", description->name, NULL, YES); - } - } - if (GPBTypeIsEnum(type)) { - if (description_->flags & GPBFieldHasEnumDescriptor) { - enumHandling_.enumDescriptor_ = - description->typeSpecific.enumDescFunc(); - } else { - enumHandling_.enumVerifier_ = description->typeSpecific.enumVerifier; - } - } - } } return self; } - (void)dealloc { - if (description_->type == GPBTypeData && + if (description_->dataType == GPBDataTypeBytes && !(description_->flags & GPBFieldRepeated)) { [defaultValue_.valueData release]; } [super dealloc]; } -- (GPBType)type { - return description_->type; +- (GPBDataType)dataType { + return description_->dataType; } - (BOOL)hasDefaultValue { @@ -530,36 +545,36 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { } } -- (GPBType)mapKeyType { +- (GPBDataType)mapKeyDataType { switch (description_->flags & GPBFieldMapKeyMask) { case GPBFieldMapKeyInt32: - return GPBTypeInt32; + return GPBDataTypeInt32; case GPBFieldMapKeyInt64: - return GPBTypeInt64; + return GPBDataTypeInt64; case GPBFieldMapKeyUInt32: - return GPBTypeUInt32; + return GPBDataTypeUInt32; case GPBFieldMapKeyUInt64: - return GPBTypeUInt64; + return GPBDataTypeUInt64; case GPBFieldMapKeySInt32: - return GPBTypeSInt32; + return GPBDataTypeSInt32; case GPBFieldMapKeySInt64: - return GPBTypeSInt64; + return GPBDataTypeSInt64; case GPBFieldMapKeyFixed32: - return GPBTypeFixed32; + return GPBDataTypeFixed32; case GPBFieldMapKeyFixed64: - return GPBTypeFixed64; + return GPBDataTypeFixed64; case GPBFieldMapKeySFixed32: - return GPBTypeSFixed32; + return GPBDataTypeSFixed32; case GPBFieldMapKeySFixed64: - return GPBTypeSFixed64; + return GPBDataTypeSFixed64; case GPBFieldMapKeyBool: - return GPBTypeBool; + return GPBDataTypeBool; case GPBFieldMapKeyString: - return GPBTypeString; + return GPBDataTypeString; default: NSAssert(0, @"Not a map type"); - return GPBTypeInt32; // For lack of anything better. + return GPBDataTypeInt32; // For lack of anything better. } } @@ -568,8 +583,8 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { } - (BOOL)isValidEnumValue:(int32_t)value { - NSAssert(description_->type == GPBTypeEnum, - @"Field Must be of type GPBTypeEnum"); + NSAssert(description_->dataType == GPBDataTypeEnum, + @"Field Must be of type GPBDataTypeEnum"); if (description_->flags & GPBFieldHasEnumDescriptor) { return enumHandling_.enumDescriptor_.enumVerifier(value); } else { @@ -585,18 +600,18 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { } } -- (GPBValue)defaultValue { +- (GPBGenericValue)defaultValue { // Depends on the fact that defaultValue_ is initialized either to "0/nil" or // to an actual defaultValue in our initializer. - GPBValue value = defaultValue_; + GPBGenericValue value = defaultValue_; if (!(description_->flags & GPBFieldRepeated)) { // We special handle data and strings. If they are nil, we replace them // with empty string/empty data. - GPBType type = description_->type; - if (type == GPBTypeData && value.valueData == nil) { + GPBDataType type = description_->dataType; + if (type == GPBDataTypeBytes && value.valueData == nil) { value.valueData = GPBEmptyNSData(); - } else if (type == GPBTypeString && value.valueString == nil) { + } else if (type == GPBDataTypeString && value.valueString == nil) { value.valueString = @""; } } @@ -635,7 +650,7 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { } // Groups vs. other fields. - if (description_->type == GPBTypeGroup) { + if (description_->dataType == GPBDataTypeGroup) { // Just capitalize the first letter. unichar firstChar = [name characterAtIndex:0]; if (firstChar >= 'a' && firstChar <= 'z') { @@ -811,16 +826,70 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { @end -@implementation GPBExtensionDescriptor +@implementation GPBExtensionDescriptor { + GPBGenericValue defaultValue_; +} + +@synthesize containingMessageClass = containingMessageClass_; - (instancetype)initWithExtensionDescription: (GPBExtensionDescription *)description { if ((self = [super init])) { description_ = description; + +#if DEBUG + const char *className = description->messageOrGroupClassName; + if (className) { + NSAssert(objc_lookUpClass(className) != Nil, + @"Class %s not defined", className); + } +#endif + + if (description->extendedClass) { + Class containingClass = objc_lookUpClass(description->extendedClass); + NSAssert(containingClass, @"Class %s not defined", + description->extendedClass); + containingMessageClass_ = containingClass; + } + + GPBDataType type = description_->dataType; + if (type == GPBDataTypeBytes) { + // Data stored as a length prefixed c-string in descriptor records. + const uint8_t *bytes = + (const uint8_t *)description->defaultValue.valueData; + if (bytes) { + uint32_t length = *((uint32_t *)bytes); + // The length is stored in network byte order. + length = ntohl(length); + bytes += sizeof(length); + defaultValue_.valueData = + [[NSData alloc] initWithBytes:bytes length:length]; + } + } else if (type == GPBDataTypeMessage || type == GPBDataTypeGroup) { + // The default is looked up in -defaultValue instead since extensions + // aren't common, we avoid the hit startup hit and it avoid initialization + // order issues. + } else { + defaultValue_ = description->defaultValue; + } } return self; } +- (void)dealloc { + if ((description_->dataType == GPBDataTypeBytes) && + !GPBExtensionIsRepeated(description_)) { + [defaultValue_.valueData release]; + } + [super dealloc]; +} + +- (instancetype)copyWithZone:(NSZone *)zone { +#pragma unused(zone) + // Immutable. + return [self retain]; +} + - (NSString *)singletonName { return @(description_->singletonName); } @@ -833,12 +902,24 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { return description_->fieldNumber; } -- (GPBType)type { - return description_->type; +- (GPBDataType)dataType { + return description_->dataType; +} + +- (GPBWireFormat)wireType { + return GPBWireFormatForType(description_->dataType, + GPBExtensionIsPacked(description_)); +} + +- (GPBWireFormat)alternateWireType { + NSAssert(GPBExtensionIsRepeated(description_), + @"Only valid on repeated extensions"); + return GPBWireFormatForType(description_->dataType, + !GPBExtensionIsPacked(description_)); } - (BOOL)isRepeated { - return (description_->options & GPBExtensionRepeated) != 0; + return GPBExtensionIsRepeated(description_); } - (BOOL)isMap { @@ -846,7 +927,7 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { } - (BOOL)isPackable { - return (description_->options & GPBExtensionPacked) != 0; + return GPBExtensionIsPacked(description_); } - (Class)msgClass { @@ -854,11 +935,63 @@ uint32_t GPBFieldTag(GPBFieldDescriptor *self) { } - (GPBEnumDescriptor *)enumDescriptor { - if (GPBTypeIsEnum(description_->type)) { + if (description_->dataType == GPBDataTypeEnum) { GPBEnumDescriptor *enumDescriptor = description_->enumDescriptorFunc(); return enumDescriptor; } return nil; } +- (id)defaultValue { + if (GPBExtensionIsRepeated(description_)) { + return nil; + } + + switch (description_->dataType) { + case GPBDataTypeBool: + return @(defaultValue_.valueBool); + case GPBDataTypeFloat: + return @(defaultValue_.valueFloat); + case GPBDataTypeDouble: + return @(defaultValue_.valueDouble); + case GPBDataTypeInt32: + case GPBDataTypeSInt32: + case GPBDataTypeEnum: + case GPBDataTypeSFixed32: + return @(defaultValue_.valueInt32); + case GPBDataTypeInt64: + case GPBDataTypeSInt64: + case GPBDataTypeSFixed64: + return @(defaultValue_.valueInt64); + case GPBDataTypeUInt32: + case GPBDataTypeFixed32: + return @(defaultValue_.valueUInt32); + case GPBDataTypeUInt64: + case GPBDataTypeFixed64: + return @(defaultValue_.valueUInt64); + case GPBDataTypeBytes: + // Like message fields, the default is zero length data. + return (defaultValue_.valueData ? defaultValue_.valueData + : GPBEmptyNSData()); + case GPBDataTypeString: + // Like message fields, the default is zero length string. + return (defaultValue_.valueString ? defaultValue_.valueString : @""); + case GPBDataTypeGroup: + case GPBDataTypeMessage: + return nil; + } +} + +- (NSComparisonResult)compareByFieldNumber:(GPBExtensionDescriptor *)other { + int32_t selfNumber = description_->fieldNumber; + int32_t otherNumber = other->description_->fieldNumber; + if (selfNumber < otherNumber) { + return NSOrderedAscending; + } else if (selfNumber == otherNumber) { + return NSOrderedSame; + } else { + return NSOrderedDescending; + } +} + @end -- cgit v1.2.3