blob: e3ff7c4059e820b29ce1fbf2a557e94b059235ec [file] [log] [blame]
Thomas Van Lenten30650d82015-05-01 08:57:16 -04001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
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
14// distribution.
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.
18//
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.
30
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040031#import "GPBExtensionRegistry.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040032
33#import "GPBBootstrap.h"
34#import "GPBDescriptor.h"
Thomas Van Lenten30650d82015-05-01 08:57:16 -040035
36@implementation GPBExtensionRegistry {
Thomas Van Lenten59110992021-02-19 09:10:47 -050037 CFMutableDictionaryRef mutableClassMap_;
Thomas Van Lenten30650d82015-05-01 08:57:16 -040038}
39
40- (instancetype)init {
41 if ((self = [super init])) {
Thomas Van Lenten59110992021-02-19 09:10:47 -050042 // The keys are ObjC classes, so straight up ptr comparisons are fine.
43 mutableClassMap_ = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL,
44 &kCFTypeDictionaryValueCallBacks);
Thomas Van Lenten30650d82015-05-01 08:57:16 -040045 }
46 return self;
47}
48
49- (void)dealloc {
Thomas Van Lenten59110992021-02-19 09:10:47 -050050 CFRelease(mutableClassMap_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -040051 [super dealloc];
52}
53
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -040054// Direct access is use for speed, to avoid even internally declaring things
55// read/write, etc. The warning is enabled in the project to ensure code calling
56// protos can turn on -Wdirect-ivar-access without issues.
57#pragma clang diagnostic push
58#pragma clang diagnostic ignored "-Wdirect-ivar-access"
59
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040060- (instancetype)copyWithZone:(NSZone *)zone {
61 GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init];
Thomas Van Lenten49e4ba62017-05-17 13:38:51 -040062 [result addExtensions:self];
Thomas Van Lenten1dcc3292015-05-21 17:14:52 -040063 return result;
64}
65
Thomas Van Lenten49e4ba62017-05-17 13:38:51 -040066- (void)addExtension:(GPBExtensionDescriptor *)extension {
67 if (extension == nil) {
68 return;
69 }
70
71 Class containingMessageClass = extension.containingMessageClass;
Thomas Van Lenten6ab51a02016-09-19 13:09:22 -040072 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)
Thomas Van Lenten59110992021-02-19 09:10:47 -050073 CFDictionaryGetValue(mutableClassMap_, containingMessageClass);
Thomas Van Lenten30650d82015-05-01 08:57:16 -040074 if (extensionMap == nil) {
Thomas Van Lenten6ab51a02016-09-19 13:09:22 -040075 // Use a custom dictionary here because the keys are numbers and conversion
76 // back and forth from NSNumber isn't worth the cost.
77 extensionMap = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL,
78 &kCFTypeDictionaryValueCallBacks);
Thomas Van Lenten59110992021-02-19 09:10:47 -050079 CFDictionarySetValue(mutableClassMap_, containingMessageClass, extensionMap);
Thomas Van Lenten49e4ba62017-05-17 13:38:51 -040080 CFRelease(extensionMap);
Thomas Van Lenten30650d82015-05-01 08:57:16 -040081 }
82
Thomas Van Lenten6ab51a02016-09-19 13:09:22 -040083 ssize_t key = extension.fieldNumber;
84 CFDictionarySetValue(extensionMap, (const void *)key, extension);
Thomas Van Lenten30650d82015-05-01 08:57:16 -040085}
86
Thomas Van Lentend846b0b2015-06-08 16:24:57 -040087- (GPBExtensionDescriptor *)extensionForDescriptor:(GPBDescriptor *)descriptor
88 fieldNumber:(NSInteger)fieldNumber {
89 Class messageClass = descriptor.messageClass;
Thomas Van Lenten6ab51a02016-09-19 13:09:22 -040090 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)
Thomas Van Lenten59110992021-02-19 09:10:47 -050091 CFDictionaryGetValue(mutableClassMap_, messageClass);
Thomas Van Lenten6ab51a02016-09-19 13:09:22 -040092 ssize_t key = fieldNumber;
93 GPBExtensionDescriptor *result =
94 (extensionMap
95 ? CFDictionaryGetValue(extensionMap, (const void *)key)
96 : nil);
97 return result;
98}
99
100static void CopyKeyValue(const void *key, const void *value, void *context) {
101 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)context;
102 CFDictionarySetValue(extensionMap, key, value);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400103}
104
Thomas Van Lenten59110992021-02-19 09:10:47 -0500105static void CopySubDictionary(const void *key, const void *value, void *context) {
106 CFMutableDictionaryRef mutableClassMap = (CFMutableDictionaryRef)context;
107 Class containingMessageClass = key;
108 CFMutableDictionaryRef otherExtensionMap = (CFMutableDictionaryRef)value;
109
110 CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)
111 CFDictionaryGetValue(mutableClassMap, containingMessageClass);
112 if (extensionMap == nil) {
113 extensionMap = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, otherExtensionMap);
114 CFDictionarySetValue(mutableClassMap, containingMessageClass, extensionMap);
115 CFRelease(extensionMap);
116 } else {
117 CFDictionaryApplyFunction(otherExtensionMap, CopyKeyValue, extensionMap);
118 }
119}
120
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400121- (void)addExtensions:(GPBExtensionRegistry *)registry {
122 if (registry == nil) {
123 // In the case where there are no extensions just ignore.
124 return;
125 }
Thomas Van Lenten59110992021-02-19 09:10:47 -0500126 CFDictionaryApplyFunction(registry->mutableClassMap_, CopySubDictionary, mutableClassMap_);
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400127}
128
Thomas Van Lentenc8a440d2016-05-25 13:46:00 -0400129#pragma clang diagnostic pop
130
Thomas Van Lenten30650d82015-05-01 08:57:16 -0400131@end