• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7
8#import "GPBExtensionRegistry.h"
9
10#import "GPBBootstrap.h"
11#import "GPBDescriptor.h"
12
13@implementation GPBExtensionRegistry {
14  CFMutableDictionaryRef mutableClassMap_;
15}
16
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;
24}
25
26- (void)dealloc {
27  CFRelease(mutableClassMap_);
28  [super dealloc];
29}
30
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"
36
37- (instancetype)copyWithZone:(NSZone *)zone {
38  GPBExtensionRegistry *result = [[[self class] allocWithZone:zone] init];
39  [result addExtensions:self];
40  return result;
41}
42
43- (void)addExtension:(GPBExtensionDescriptor *)extension {
44  if (extension == nil) {
45    return;
46  }
47
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  }
59
60  ssize_t key = extension.fieldNumber;
61  CFDictionarySetValue(extensionMap, (const void *)key, extension);
62}
63
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;
73}
74
75static void CopyKeyValue(const void *key, const void *value, void *context) {
76  CFMutableDictionaryRef extensionMap = (CFMutableDictionaryRef)context;
77  CFDictionarySetValue(extensionMap, key, value);
78}
79
80static void CopySubDictionary(const void *key, const void *value, void *context) {
81  CFMutableDictionaryRef mutableClassMap = (CFMutableDictionaryRef)context;
82  Class containingMessageClass = key;
83  CFMutableDictionaryRef otherExtensionMap = (CFMutableDictionaryRef)value;
84
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  }
94}
95
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_);
102}
103
104#pragma clang diagnostic pop
105
106@end
107