1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #import "GPBExtensionRegistry.h"
33 #import "GPBBootstrap.h"
34 #import "GPBDescriptor.h"
36 @implementation GPBExtensionRegistry {
37 NSMutableDictionary *mutableClassMap_;
40 - (instancetype)init {
41 if ((self = [super init])) {
42 mutableClassMap_ = [[NSMutableDictionary alloc] init];
48 [mutableClassMap_ release];
52 // Direct access is use for speed, to avoid even internally declaring things
53 // read/write, etc. The warning is enabled in the project to ensure code calling
54 // protos can turn on -Wdirect-ivar-access without issues.
55 #pragma clang diagnostic push
56 #pragma clang diagnostic ignored "-Wdirect-ivar-access"
58 - (instancetype)copyWithZone:(NSZone *)zone {
59 GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init];
60 [result addExtensions:self];
64 - (void)addExtension:(GPBExtensionDescriptor *)extension {
65 if (extension == nil) {
69 Class containingMessageClass = extension.containingMessageClass;
70 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)
71 [mutableClassMap_ objectForKey:containingMessageClass];
72 if (extensionMap == nil) {
73 // Use a custom dictionary here because the keys are numbers and conversion
74 // back and forth from NSNumber isn't worth the cost.
75 extensionMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL,
76 &kCFTypeDictionaryValueCallBacks);
77 [mutableClassMap_ setObject:(id)extensionMap
78 forKey:(id<NSCopying>)containingMessageClass];
79 CFRelease(extensionMap);
82 ssize_t key = extension.fieldNumber;
83 CFDictionarySetValue(extensionMap, (const void *)key, extension);
86 - (GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor
87 fieldNumber:(NSInteger)fieldNumber {
88 Class messageClass = descriptor.messageClass;
89 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)
90 [mutableClassMap_ objectForKey:messageClass];
91 ssize_t key = fieldNumber;
92 GPBExtensionDescriptor *result =
94 ? CFDictionaryGetValue(extensionMap, (const void *)key)
99 static void CopyKeyValue(const void *key, const void *value, void *context) {
100 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)context;
101 CFDictionarySetValue(extensionMap, key, value);
104 - (void)addExtensions:(GPBExtensionRegistry *)registry {
105 if (registry == nil) {
106 // In the case where there are no extensions just ignore.
109 NSMutableDictionary *otherClassMap = registry->mutableClassMap_;
110 [otherClassMap enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL * stop) {
112 Class containingMessageClass = key;
113 CFMutableDictionaryRef otherExtensionMap = (CFMutableDictionaryRef)value;
115 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)
116 [mutableClassMap_ objectForKey:containingMessageClass];
117 if (extensionMap == nil) {
118 extensionMap = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, otherExtensionMap);
119 [mutableClassMap_ setObject:(id)extensionMap
120 forKey:(id<NSCopying>)containingMessageClass];
121 CFRelease(extensionMap);
123 CFDictionaryApplyFunction(otherExtensionMap, CopyKeyValue, extensionMap);
128 #pragma clang diagnostic pop