diff options
Diffstat (limited to 'objectivec/GPBExtensionRegistry.m')
-rw-r--r-- | objectivec/GPBExtensionRegistry.m | 80 |
1 files changed, 51 insertions, 29 deletions
diff --git a/objectivec/GPBExtensionRegistry.m b/objectivec/GPBExtensionRegistry.m index df61a17b..b056a52d 100644 --- a/objectivec/GPBExtensionRegistry.m +++ b/objectivec/GPBExtensionRegistry.m @@ -34,8 +34,6 @@ #import "GPBDescriptor.h" @implementation GPBExtensionRegistry { - // TODO(dmaclach): Reimplement with CFDictionaries that don't use - // objects as keys. NSMutableDictionary *mutableClassMap_; } @@ -51,43 +49,56 @@ [super dealloc]; } +// Direct access is use for speed, to avoid even internally declaring things +// read/write, etc. The warning is enabled in the project to ensure code calling +// protos can turn on -Wdirect-ivar-access without issues. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdirect-ivar-access" + - (instancetype)copyWithZone:(NSZone *)zone { GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init]; - if (result && mutableClassMap_.count) { - [result->mutableClassMap_ addEntriesFromDictionary:mutableClassMap_]; - } + [result addExtensions:self]; return result; } -- (NSMutableDictionary *)extensionMapForContainingMessageClass: - (Class)containingMessageClass { - NSMutableDictionary *extensionMap = - [mutableClassMap_ objectForKey:containingMessageClass]; - if (extensionMap == nil) { - extensionMap = [NSMutableDictionary dictionary]; - [mutableClassMap_ setObject:extensionMap - forKey:(id<NSCopying>)containingMessageClass]; - } - return extensionMap; -} - - (void)addExtension:(GPBExtensionDescriptor *)extension { if (extension == nil) { return; } Class containingMessageClass = extension.containingMessageClass; - NSMutableDictionary *extensionMap = - [self extensionMapForContainingMessageClass:containingMessageClass]; - [extensionMap setObject:extension forKey:@(extension.fieldNumber)]; + CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) + [mutableClassMap_ objectForKey:containingMessageClass]; + if (extensionMap == nil) { + // Use a custom dictionary here because the keys are numbers and conversion + // back and forth from NSNumber isn't worth the cost. + extensionMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, + &kCFTypeDictionaryValueCallBacks); + [mutableClassMap_ setObject:(id)extensionMap + forKey:(id<NSCopying>)containingMessageClass]; + CFRelease(extensionMap); + } + + ssize_t key = extension.fieldNumber; + CFDictionarySetValue(extensionMap, (const void *)key, extension); } - (GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor fieldNumber:(NSInteger)fieldNumber { Class messageClass = descriptor.messageClass; - NSDictionary *extensionMap = + CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) [mutableClassMap_ objectForKey:messageClass]; - return [extensionMap objectForKey:@(fieldNumber)]; + ssize_t key = fieldNumber; + GPBExtensionDescriptor *result = + (extensionMap + ? CFDictionaryGetValue(extensionMap, (const void *)key) + : nil); + return result; +} + +static void CopyKeyValue(const void *key, const void *value, void *context) { + CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)context; + CFDictionarySetValue(extensionMap, key, value); } - (void)addExtensions:(GPBExtensionRegistry *)registry { @@ -96,13 +107,24 @@ return; } NSMutableDictionary *otherClassMap = registry->mutableClassMap_; - for (Class containingMessageClass in otherClassMap) { - NSMutableDictionary *extensionMap = - [self extensionMapForContainingMessageClass:containingMessageClass]; - NSMutableDictionary *otherExtensionMap = - [registry extensionMapForContainingMessageClass:containingMessageClass]; - [extensionMap addEntriesFromDictionary:otherExtensionMap]; - } + [otherClassMap enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL * stop) { +#pragma unused(stop) + Class containingMessageClass = key; + CFMutableDictionaryRef otherExtensionMap = (CFMutableDictionaryRef)value; + + CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef) + [mutableClassMap_ objectForKey:containingMessageClass]; + if (extensionMap == nil) { + extensionMap = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, otherExtensionMap); + [mutableClassMap_ setObject:(id)extensionMap + forKey:(id<NSCopying>)containingMessageClass]; + CFRelease(extensionMap); + } else { + CFDictionaryApplyFunction(otherExtensionMap, CopyKeyValue, extensionMap); + } + }]; } +#pragma clang diagnostic pop + @end |