Add tests for older gcc versions we still support
[google-protobuf.git] / objectivec / GPBExtensionRegistry.m
blobc76ca11c2bb877c34c4806efe46c3fdbe7ea71b0
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
8 #import "GPBExtensionRegistry.h"
10 #import "GPBBootstrap.h"
11 #import "GPBDescriptor.h"
13 @implementation GPBExtensionRegistry {
14   CFMutableDictionaryRef mutableClassMap_;
17 - (instancetype)init {
18   if ((self = [super init])) {
19     // The keys are ObjC classes, so straight up ptr comparisons are fine.
20     mutableClassMap_ =
21         CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
22   }
23   return self;
26 - (void)dealloc {
27   CFRelease(mutableClassMap_);
28   [super dealloc];
31 // Direct access is use for speed, to avoid even internally declaring things
32 // read/write, etc. The warning is enabled in the project to ensure code calling
33 // protos can turn on -Wdirect-ivar-access without issues.
34 #pragma clang diagnostic push
35 #pragma clang diagnostic ignored "-Wdirect-ivar-access"
37 - (instancetype)copyWithZone:(NSZone *)zone {
38   GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init];
39   [result addExtensions:self];
40   return result;
43 - (void)addExtension:(GPBExtensionDescriptor *)extension {
44   if (extension == nil) {
45     return;
46   }
48   Class containingMessageClass = extension.containingMessageClass;
49   CFMutableDictionaryRef extensionMap =
50       (CFMutableDictionaryRef)CFDictionaryGetValue(mutableClassMap_, containingMessageClass);
51   if (extensionMap == nil) {
52     // Use a custom dictionary here because the keys are numbers and conversion
53     // back and forth from NSNumber isn't worth the cost.
54     extensionMap =
55         CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
56     CFDictionarySetValue(mutableClassMap_, containingMessageClass, extensionMap);
57     CFRelease(extensionMap);
58   }
60   ssize_t key = extension.fieldNumber;
61   CFDictionarySetValue(extensionMap, (const void *)key, extension);
64 - (GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor
65                                        fieldNumber:(NSInteger)fieldNumber {
66   Class messageClass = descriptor.messageClass;
67   CFMutableDictionaryRef extensionMap =
68       (CFMutableDictionaryRef)CFDictionaryGetValue(mutableClassMap_, messageClass);
69   ssize_t key = fieldNumber;
70   GPBExtensionDescriptor *result =
71       (extensionMap ? CFDictionaryGetValue(extensionMap, (const void *)key) : nil);
72   return result;
75 static void CopyKeyValue(const void *key, const void *value, void *context) {
76   CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)context;
77   CFDictionarySetValue(extensionMap, key, value);
80 static void CopySubDictionary(const void *key, const void *value, void *context) {
81   CFMutableDictionaryRef mutableClassMap = (CFMutableDictionaryRef)context;
82   Class containingMessageClass = key;
83   CFMutableDictionaryRef otherExtensionMap = (CFMutableDictionaryRef)value;
85   CFMutableDictionaryRef extensionMap =
86       (CFMutableDictionaryRef)CFDictionaryGetValue(mutableClassMap, containingMessageClass);
87   if (extensionMap == nil) {
88     extensionMap = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, otherExtensionMap);
89     CFDictionarySetValue(mutableClassMap, containingMessageClass, extensionMap);
90     CFRelease(extensionMap);
91   } else {
92     CFDictionaryApplyFunction(otherExtensionMap, CopyKeyValue, extensionMap);
93   }
96 - (void)addExtensions:(GPBExtensionRegistry *)registry {
97   if (registry == nil) {
98     // In the case where there are no extensions just ignore.
99     return;
100   }
101   CFDictionaryApplyFunction(registry->mutableClassMap_, CopySubDictionary, mutableClassMap_);
104 #pragma clang diagnostic pop
106 @end