aboutsummaryrefslogtreecommitdiff
path: root/objectivec/GPBDescriptor.m
diff options
context:
space:
mode:
authorThomas Van Lenten <thomasvl@google.com>2015-06-08 16:24:57 -0400
committerThomas Van Lenten <thomasvl@google.com>2015-06-08 17:17:22 -0400
commitd846b0b059b4d867536b98aa29475a387aa09114 (patch)
tree25ebf99cd0462281add17fc94bdf185e5fd9096c /objectivec/GPBDescriptor.m
parent3f9be70d067fb03cd03f99522473dee265b84ddb (diff)
downloadprotobuf-d846b0b059b4d867536b98aa29475a387aa09114.tar.gz
protobuf-d846b0b059b4d867536b98aa29475a387aa09114.tar.bz2
protobuf-d846b0b059b4d867536b98aa29475a387aa09114.zip
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.
Diffstat (limited to 'objectivec/GPBDescriptor.m')
-rw-r--r--objectivec/GPBDescriptor.m307
1 files changed, 220 insertions, 87 deletions
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