Compare commits

..

No commits in common. "signal-master" and "master" have entirely different histories.

7 changed files with 147 additions and 328 deletions

View File

@ -1,30 +0,0 @@
{
"name": "Mantle",
"version": "2.1.0",
"summary": "Model framework for Cocoa and Cocoa Touch.",
"homepage": "https://github.com/Mantle/Mantle",
"license": "MIT",
"authors": {
"Github": "support@github.com"
},
"source": {
"git": "https://github.com/github/Mantle.git",
"tag": "2.1.0"
},
"platforms": {
"ios": "5.0",
"osx": "10.7",
"watchos": "2.0",
"tvos": "9.0"
},
"requires_arc": true,
"frameworks": "Foundation",
"source_files": "Mantle",
"subspecs": [
{
"name": "extobjc",
"source_files": "Mantle/extobjc",
"private_header_files": "Mantle/extobjc/*.h"
}
]
}

View File

@ -359,18 +359,7 @@ NSString * const MTLJSONAdapterThrownExceptionErrorKey = @"MTLJSONAdapterThrownE
id model = [self.modelClass modelWithDictionary:dictionaryValue error:error];
// BEGIN ORM-PERF-2
// Commented out by mkirk as part of ORM perf optimizations.
//
// The validation NSCoding validation reflection used by Mantle is expensive, and
// we've never used it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
//
// return [model validate:error] ? model : nil;
//
return model;
// END ORM-PERF-2
return [model validate:error] ? model : nil;
}
+ (NSDictionary *)valueTransformersForModelClass:(Class)modelClass {

View File

@ -17,15 +17,6 @@ static NSString * const MTLModelVersionKey = @"MTLModelVersion";
// Used to cache the reflection performed in +allowedSecureCodingClassesByPropertyKey.
static void *MTLModelCachedAllowedClassesKey = &MTLModelCachedAllowedClassesKey;
// BEGIN ORM-PERF-3
// Added by mkirk as part of ORM perf optimizations.
//
// +encodingBehaviorsByPropertyKey is somewhat expensive, so we follow existing library patterns
// to cache the computed reflection on the class via an associated object
// Used to cache the reflection performed in +encodingBehaviorsByPropertyKey.
static void *MTLModelCachedEncodingBehaviorsByPropertyKeyKey = &MTLModelCachedEncodingBehaviorsByPropertyKeyKey;
// END ORM-PERF-3
// Returns whether the given NSCoder requires secure coding.
static BOOL coderRequiresSecureCoding(NSCoder *coder) {
SEL requiresSecureCodingSelector = @selector(requiresSecureCoding);
@ -72,15 +63,6 @@ static void verifyAllowedClassesByPropertyKey(Class modelClass) {
#pragma mark Encoding Behaviors
+ (NSDictionary *)encodingBehaviorsByPropertyKey {
// BEGIN ORM-PERF-3
// Added by mkirk as part of ORM perf optimizations.
//
// +encodingBehaviorsByPropertyKey is somewhat expensive, so we follow existing library patterns
// to cache the computed reflection on the class via an associated object
NSDictionary *cachedBehaviors = objc_getAssociatedObject(self, MTLModelCachedEncodingBehaviorsByPropertyKeyKey);
if (cachedBehaviors != nil) return cachedBehaviors;
// END ORM-PERF-3
NSSet *propertyKeys = self.propertyKeys;
NSMutableDictionary *behaviors = [[NSMutableDictionary alloc] initWithCapacity:propertyKeys.count];
@ -97,14 +79,6 @@ static void verifyAllowedClassesByPropertyKey(Class modelClass) {
behaviors[key] = @(behavior);
}
// BEGIN ORM-PERF-3
// Added by mkirk as part of ORM perf optimizations.
//
// +encodingBehaviorsByPropertyKey is somewhat expensive, so we follow existing library patterns
// to cache the computed reflection on the class via an associated object
objc_setAssociatedObject(self, MTLModelCachedEncodingBehaviorsByPropertyKeyKey, behaviors, OBJC_ASSOCIATION_COPY);
// END ORM-PERF-3
return behaviors;
}
@ -152,21 +126,14 @@ static void verifyAllowedClassesByPropertyKey(Class modelClass) {
NSParameterAssert(key != nil);
NSParameterAssert(coder != nil);
// BEGIN ORM-PERF-1
// Commented out by mkirk as part of ORM perf optimizations.
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
// and we're not using the reflective features that require it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
// SEL selector = MTLSelectorWithCapitalizedKeyPattern("decode", key, "WithCoder:modelVersion:");
// if ([self respondsToSelector:selector]) {
// IMP imp = [self methodForSelector:selector];
// id (*function)(id, SEL, NSCoder *, NSUInteger) = (__typeof__(function))imp;
// id result = function(self, selector, coder, modelVersion);
//
// return result;
// }
// END ORM-PERF-1
SEL selector = MTLSelectorWithCapitalizedKeyPattern("decode", key, "WithCoder:modelVersion:");
if ([self respondsToSelector:selector]) {
IMP imp = [self methodForSelector:selector];
id (*function)(id, SEL, NSCoder *, NSUInteger) = (__typeof__(function))imp;
id result = function(self, selector, coder, modelVersion);
return result;
}
@try {
if (coderRequiresSecureCoding(coder)) {

View File

@ -48,7 +48,7 @@ typedef enum : NSUInteger {
/// (like a KVC validation error).
///
/// Returns an initialized model object, or nil if validation failed.
+ (instancetype)modelWithDictionary:(NSDictionary<NSString *, id> *)dictionaryValue error:(NSError **)error;
+ (instancetype)modelWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;
/// A dictionary representing the properties of the receiver.
///
@ -56,7 +56,7 @@ typedef enum : NSUInteger {
/// with any nil values represented by NSNull.
///
/// This property must never be nil.
@property (nonatomic, copy, readonly) NSDictionary<NSString *, id> *dictionaryValue;
@property (nonatomic, copy, readonly) NSDictionary *dictionaryValue;
/// Initializes the receiver using key-value coding, setting the keys and values
/// in the given dictionary.
@ -74,22 +74,15 @@ typedef enum : NSUInteger {
/// (like a KVC validation error).
///
/// Returns an initialized model object, or nil if validation failed.
- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dictionaryValue error:(NSError **)error;
- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;
// BEGIN ORM-PERF-1
// Commented out by mkirk as part of ORM perf optimizations.
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
// and we're not using the reflective features that require it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
/// Merges the value of the given key on the receiver with the value of the same
/// key from the given model object, giving precedence to the other model object.
//- (void)mergeValueForKey:(NSString *)key fromModel:(id<MTLModel>)model;
// END ORM-PERF-1
- (void)mergeValueForKey:(NSString *)key fromModel:(id<MTLModel>)model;
/// Returns the keys for all @property declarations, except for `readonly`
/// properties without ivars, or properties on MTLModel itself.
+ (NSSet<NSString *> *)propertyKeys;
+ (NSSet *)propertyKeys;
/// Validates the model.
///
@ -97,7 +90,7 @@ typedef enum : NSUInteger {
/// validation
///
/// Returns YES if the model is valid, or NO if the validation failed.
//- (BOOL)validate:(NSError **)error;
- (BOOL)validate:(NSError **)error;
@end
@ -120,31 +113,23 @@ typedef enum : NSUInteger {
/// (like a KVC validation error).
///
/// Returns an initialized model object, or nil if validation failed.
- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dictionaryValue error:(NSError **)error;
- (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;
/// Initializes the receiver with default values.
///
/// This is the designated initializer for this class.
- (instancetype)init;
// BEGIN ORM-PERF-1
// Commented out by mkirk as part of ORM perf optimizations.
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
// and we're not using the reflective features that require it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
/// By default, this method looks for a `-merge<Key>FromModel:` method on the
/// receiver, and invokes it if found. If not found, and `model` is not nil, the
/// value for the given key is taken from `model`.
//- (void)mergeValueForKey:(NSString *)key fromModel:(id<MTLModel>)model;
//
- (void)mergeValueForKey:(NSString *)key fromModel:(id<MTLModel>)model;
/// Merges the values of the given model object into the receiver, using
/// -mergeValueForKey:fromModel: for each key in +propertyKeys.
///
/// `model` must be an instance of the receiver's class or a subclass thereof.
//- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model;
//
// END ORM-PERF-1
- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model;
/// The storage behavior of a given key.
///
@ -176,29 +161,19 @@ typedef enum : NSUInteger {
@end
// BEGIN ORM-PERF-2
// Commented out by mkirk as part of ORM perf optimizations.
//
// The validation NSCoding validation reflection used by Mantle is expensive, and
// we've never used it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
//
///// Implements validation logic for MTLModel.
//@interface MTLModel (Validation)
//
///// Validates the model.
/////
///// The default implementation simply invokes -validateValue:forKey:error: with
///// all +propertyKeys and their current value. If -validateValue:forKey:error:
///// returns a new value, the property is set to that new value.
/////
///// error - If not NULL, this may be set to any error that occurs during
///// validation
/////
///// Returns YES if the model is valid, or NO if the validation failed.
//- (BOOL)validate:(NSError **)error;
//
//@end
//
// END ORM-PERF-2
/// Implements validation logic for MTLModel.
@interface MTLModel (Validation)
/// Validates the model.
///
/// The default implementation simply invokes -validateValue:forKey:error: with
/// all +propertyKeys and their current value. If -validateValue:forKey:error:
/// returns a new value, the property is set to that new value.
///
/// error - If not NULL, this may be set to any error that occurs during
/// validation
///
/// Returns YES if the model is valid, or NO if the validation failed.
- (BOOL)validate:(NSError **)error;
@end

View File

@ -24,24 +24,6 @@ static void *MTLModelCachedTransitoryPropertyKeysKey = &MTLModelCachedTransitory
// property keys.
static void *MTLModelCachedPermanentPropertyKeysKey = &MTLModelCachedPermanentPropertyKeysKey;
// BEGIN ORM-PERF-4
// Added by mkirk as part of ORM perf optimizations.
//
// +dictionaryValueKeys is somewhat expensive, so we follow existing library patterns
// to cache the computed reflection on the class via an associated object
//
// Used to cache the reflection performed in +dictionaryValueKeys
static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryValueKeysKey;
// END ORM-PERF-4
// BEGIN ORM-PERF-2
// Commented out by mkirk as part of ORM perf optimizations.
//
// The validation NSCoding validation reflection used by Mantle is expensive, and
// we've never used it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
//
// Validates a value for an object and sets it if necessary.
//
// obj - The object for which the value is being validated. This value
@ -56,36 +38,35 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
//
// Returns YES if `value` could be validated and set, or NO if an error
// occurred.
//static BOOL MTLValidateAndSetValue(id obj, NSString *key, id value, BOOL forceUpdate, NSError **error) {
// // Mark this as being autoreleased, because validateValue may return
// // a new object to be stored in this variable (and we don't want ARC to
// // double-free or leak the old or new values).
// __autoreleasing id validatedValue = value;
//
// @try {
// if (![obj validateValue:&validatedValue forKey:key error:error]) return NO;
//
// if (forceUpdate || value != validatedValue) {
// [obj setValue:validatedValue forKey:key];
// }
//
// return YES;
// } @catch (NSException *ex) {
// NSLog(@"*** Caught exception setting key \"%@\" : %@", key, ex);
//
// // Fail fast in Debug builds.
// #if DEBUG
// @throw ex;
// #else
// if (error != NULL) {
// *error = [NSError mtl_modelErrorWithException:ex];
// }
//
// return NO;
// #endif
// }
//}
// END ORM-PERF-2
static BOOL MTLValidateAndSetValue(id obj, NSString *key, id value, BOOL forceUpdate, NSError **error) {
// Mark this as being autoreleased, because validateValue may return
// a new object to be stored in this variable (and we don't want ARC to
// double-free or leak the old or new values).
__autoreleasing id validatedValue = value;
@try {
if (![obj validateValue:&validatedValue forKey:key error:error]) return NO;
if (forceUpdate || value != validatedValue) {
[obj setValue:validatedValue forKey:key];
}
return YES;
} @catch (NSException *ex) {
NSLog(@"*** Caught exception setting key \"%@\" : %@", key, ex);
// Fail fast in Debug builds.
#if DEBUG
@throw ex;
#else
if (error != NULL) {
*error = [NSError mtl_modelErrorWithException:ex];
}
return NO;
#endif
}
}
@interface MTLModel ()
@ -95,11 +76,11 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
// Returns a set of all property keys for which
// +storageBehaviorForPropertyWithKey returned MTLPropertyStorageTransitory.
+ (NSSet<NSString *> *)transitoryPropertyKeys;
+ (NSSet *)transitoryPropertyKeys;
// Returns a set of all property keys for which
// +storageBehaviorForPropertyWithKey returned MTLPropertyStoragePermanent.
+ (NSSet<NSString *> *)permanentPropertyKeys;
+ (NSSet *)permanentPropertyKeys;
// Enumerates all properties of the receiver's class hierarchy, starting at the
// receiver, and continuing up until (but not including) MTLModel.
@ -115,8 +96,8 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
#pragma mark Lifecycle
+ (void)generateAndCacheStorageBehaviors {
NSMutableSet<NSString *> *transitoryKeys = [NSMutableSet set];
NSMutableSet<NSString *> *permanentKeys = [NSMutableSet set];
NSMutableSet *transitoryKeys = [NSMutableSet set];
NSMutableSet *permanentKeys = [NSMutableSet set];
for (NSString *propertyKey in self.propertyKeys) {
switch ([self storageBehaviorForPropertyWithKey:propertyKey]) {
@ -139,7 +120,7 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
objc_setAssociatedObject(self, MTLModelCachedPermanentPropertyKeysKey, permanentKeys, OBJC_ASSOCIATION_COPY);
}
+ (instancetype)modelWithDictionary:(NSDictionary<NSString *, id> *)dictionary error:(NSError **)error {
+ (instancetype)modelWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {
return [[self alloc] initWithDictionary:dictionary error:error];
}
@ -148,7 +129,7 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
return [super init];
}
- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dictionary error:(NSError **)error {
- (instancetype)initWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {
self = [self init];
if (self == nil) return nil;
@ -159,18 +140,9 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
__autoreleasing id value = [dictionary objectForKey:key];
if ([value isEqual:NSNull.null]) value = nil;
// BEGIN ORM-PERF-2
// Commented out by mkirk as part of ORM perf optimizations.
//
// The validation NSCoding validation reflection used by Mantle is expensive, and
// we've never used it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
//
// BOOL success = MTLValidateAndSetValue(self, key, value, YES, error);
// if (!success) return nil;
[self setValue:value forKey:key];
// END ORM-PERF-2
BOOL success = MTLValidateAndSetValue(self, key, value, YES, error);
if (!success) return nil;
}
return self;
@ -200,11 +172,11 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
}
}
+ (NSSet<NSString *> *)propertyKeys {
NSSet<NSString *> *cachedKeys = objc_getAssociatedObject(self, MTLModelCachedPropertyKeysKey);
+ (NSSet *)propertyKeys {
NSSet *cachedKeys = objc_getAssociatedObject(self, MTLModelCachedPropertyKeysKey);
if (cachedKeys != nil) return cachedKeys;
NSMutableSet<NSString *> *keys = [NSMutableSet set];
NSMutableSet *keys = [NSMutableSet set];
[self enumeratePropertiesUsingBlock:^(objc_property_t property, BOOL *stop) {
NSString *key = @(property_getName(property));
@ -221,8 +193,8 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
return keys;
}
+ (NSSet<NSString *> *)transitoryPropertyKeys {
NSSet<NSString *> *transitoryPropertyKeys = objc_getAssociatedObject(self, MTLModelCachedTransitoryPropertyKeysKey);
+ (NSSet *)transitoryPropertyKeys {
NSSet *transitoryPropertyKeys = objc_getAssociatedObject(self, MTLModelCachedTransitoryPropertyKeysKey);
if (transitoryPropertyKeys == nil) {
[self generateAndCacheStorageBehaviors];
@ -232,8 +204,8 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
return transitoryPropertyKeys;
}
+ (NSSet<NSString *> *)permanentPropertyKeys {
NSSet<NSString *> *permanentPropertyKeys = objc_getAssociatedObject(self, MTLModelCachedPermanentPropertyKeysKey);
+ (NSSet *)permanentPropertyKeys {
NSSet *permanentPropertyKeys = objc_getAssociatedObject(self, MTLModelCachedPermanentPropertyKeysKey);
if (permanentPropertyKeys == nil) {
[self generateAndCacheStorageBehaviors];
@ -243,28 +215,11 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
return permanentPropertyKeys;
}
// BEGIN ORM-PERF-4
// Added by mkirk as part of ORM perf optimizations.
//
// +dictionaryValueKeys is somewhat expensive, so we follow existing library patterns
// to cache the computed reflection on the class via an associated object
//
// Used to cache the reflection performed in +dictionaryValueKeys
+ (NSArray<NSString *> *)dictionaryValueKeys {
NSArray<NSString *> *dictionaryValueKeys = objc_getAssociatedObject(self, MTLModelCachedDictionaryValueKeysKey);
if (!dictionaryValueKeys) {
NSSet<NSString *> *keys = [self.class.transitoryPropertyKeys setByAddingObjectsFromSet:self.permanentPropertyKeys];
dictionaryValueKeys = keys.allObjects;
objc_setAssociatedObject(self, MTLModelCachedDictionaryValueKeysKey, dictionaryValueKeys, OBJC_ASSOCIATION_COPY);
}
return dictionaryValueKeys;
}
- (NSDictionary *)dictionaryValue {
NSSet *keys = [self.class.transitoryPropertyKeys setByAddingObjectsFromSet:self.class.permanentPropertyKeys];
- (NSDictionary<NSString *, id> *)dictionaryValue {
NSArray<NSString *> *keys = self.class.dictionaryValueKeys;
return [self dictionaryWithValuesForKeys:keys];
return [self dictionaryWithValuesForKeys:keys.allObjects];
}
// END ORM-PERF-4
+ (MTLPropertyStorage)storageBehaviorForPropertyWithKey:(NSString *)propertyKey {
objc_property_t property = class_getProperty(self.class, propertyKey.UTF8String);
@ -295,61 +250,45 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
#pragma mark Merging
// BEGIN ORM-PERF-1
// Commented out by mkirk as part of ORM perf optimizations.
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
// and we're not using the reflective features that require it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
//
//- (void)mergeValueForKey:(NSString *)key fromModel:(NSObject<MTLModel> *)model {
// NSParameterAssert(key != nil);
//
//// SEL selector = MTLSelectorWithCapitalizedKeyPattern("merge", key, "FromModel:");
//// if (![self respondsToSelector:selector]) {
//// if (model != nil) {
//// [self setValue:[model valueForKey:key] forKey:key];
//// }
////
//// return;
//// }
//
// IMP imp = [self methodForSelector:selector];
// void (*function)(id, SEL, id<MTLModel>) = (__typeof__(function))imp;
// function(self, selector, model);
//}
//
//- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model {
// NSSet<NSString *> *propertyKeys = model.class.propertyKeys;
//
// for (NSString *key in self.class.propertyKeys) {
// if (![propertyKeys containsObject:key]) continue;
//
// [self mergeValueForKey:key fromModel:model];
// }
//}
// END ORM-PERF-1
- (void)mergeValueForKey:(NSString *)key fromModel:(NSObject<MTLModel> *)model {
NSParameterAssert(key != nil);
// BEGIN ORM-PERF-2
// Commented out by mkirk as part of ORM perf optimizations.
//
// The validation NSCoding validation reflection used by Mantle is expensive, and
// we've never used it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
//#pragma mark Validation
//
//- (BOOL)validate:(NSError **)error {
// for (NSString *key in self.class.propertyKeys) {
// id value = [self valueForKey:key];
//
// BOOL success = MTLValidateAndSetValue(self, key, value, NO, error);
// if (!success) return NO;
// }
//
// return YES;
//}
// END ORM-PERF-2
SEL selector = MTLSelectorWithCapitalizedKeyPattern("merge", key, "FromModel:");
if (![self respondsToSelector:selector]) {
if (model != nil) {
[self setValue:[model valueForKey:key] forKey:key];
}
return;
}
IMP imp = [self methodForSelector:selector];
void (*function)(id, SEL, id<MTLModel>) = (__typeof__(function))imp;
function(self, selector, model);
}
- (void)mergeValuesForKeysFromModel:(id<MTLModel>)model {
NSSet *propertyKeys = model.class.propertyKeys;
for (NSString *key in self.class.propertyKeys) {
if (![propertyKeys containsObject:key]) continue;
[self mergeValueForKey:key fromModel:model];
}
}
#pragma mark Validation
- (BOOL)validate:(NSError **)error {
for (NSString *key in self.class.propertyKeys) {
id value = [self valueForKey:key];
BOOL success = MTLValidateAndSetValue(self, key, value, NO, error);
if (!success) return NO;
}
return YES;
}
#pragma mark NSCopying
@ -362,13 +301,9 @@ static void *MTLModelCachedDictionaryValueKeysKey = &MTLModelCachedDictionaryVal
#pragma mark NSObject
- (NSString *)description {
#if DEBUG
NSDictionary<NSString *, id> *permanentProperties = [self dictionaryWithValuesForKeys:self.class.permanentPropertyKeys.allObjects];
NSDictionary *permanentProperties = [self dictionaryWithValuesForKeys:self.class.permanentPropertyKeys.allObjects];
return [NSString stringWithFormat:@"<%@: %p> %@", self.class, self, permanentProperties];
#else
return [NSString stringWithFormat:@"<%@: %p>", self.class, self];
#endif
}
- (NSUInteger)hash {

View File

@ -18,14 +18,6 @@
/// selector.
SEL MTLSelectorWithKeyPattern(NSString *key, const char *suffix) __attribute__((pure, nonnull(1, 2)));
// BEGIN ORM-PERF-1
// Commented out by mkirk as part of ORM perf optimizations.
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
// and we're not using the reflective features that require it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
//
/// Creates a selector from a key and a constant prefix and suffix.
///
/// prefix - A string to prepend to the key as part of the selector.
@ -36,6 +28,4 @@ SEL MTLSelectorWithKeyPattern(NSString *key, const char *suffix) __attribute__((
///
/// Returns a selector, or NULL if the input strings cannot form a valid
/// selector.
//SEL MTLSelectorWithCapitalizedKeyPattern(const char *prefix, NSString *key, const char *suffix) __attribute__((pure, nonnull(1, 2, 3)));
//
// END ORM-PERF-1
SEL MTLSelectorWithCapitalizedKeyPattern(const char *prefix, NSString *key, const char *suffix) __attribute__((pure, nonnull(1, 2, 3)));

View File

@ -24,34 +24,27 @@ SEL MTLSelectorWithKeyPattern(NSString *key, const char *suffix) {
return sel_registerName(selector);
}
// BEGIN ORM-PERF-1
// Commented out by mkirk as part of ORM perf optimizations.
// The `MTLSelectorWithCapitalizedKeyPattern` can be quite expensive in aggregate
// and we're not using the reflective features that require it.
// If we later want to use this feature, we'll need to carefully evaluate the perf
// implications on large migrations.
//SEL MTLSelectorWithCapitalizedKeyPattern(const char *prefix, NSString *key, const char *suffix) {
// NSUInteger prefixLength = strlen(prefix);
// NSUInteger suffixLength = strlen(suffix);
//
// NSString *initial = [key substringToIndex:1].uppercaseString;
// NSUInteger initialLength = [initial maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
//
// NSString *rest = [key substringFromIndex:1];
// NSUInteger restLength = [rest maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
//
// char selector[prefixLength + initialLength + restLength + suffixLength + 1];
// memcpy(selector, prefix, prefixLength);
//
// BOOL success = [initial getBytes:selector + prefixLength maxLength:initialLength usedLength:&initialLength encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0, initial.length) remainingRange:NULL];
// if (!success) return NULL;
//
// success = [rest getBytes:selector + prefixLength + initialLength maxLength:restLength usedLength:&restLength encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0, rest.length) remainingRange:NULL];
// if (!success) return NULL;
//
// memcpy(selector + prefixLength + initialLength + restLength, suffix, suffixLength);
// selector[prefixLength + initialLength + restLength + suffixLength] = '\0';
//
// return sel_registerName(selector);
//}
// END ORM-PERF-1
SEL MTLSelectorWithCapitalizedKeyPattern(const char *prefix, NSString *key, const char *suffix) {
NSUInteger prefixLength = strlen(prefix);
NSUInteger suffixLength = strlen(suffix);
NSString *initial = [key substringToIndex:1].uppercaseString;
NSUInteger initialLength = [initial maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSString *rest = [key substringFromIndex:1];
NSUInteger restLength = [rest maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
char selector[prefixLength + initialLength + restLength + suffixLength + 1];
memcpy(selector, prefix, prefixLength);
BOOL success = [initial getBytes:selector + prefixLength maxLength:initialLength usedLength:&initialLength encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0, initial.length) remainingRange:NULL];
if (!success) return NULL;
success = [rest getBytes:selector + prefixLength + initialLength maxLength:restLength usedLength:&restLength encoding:NSUTF8StringEncoding options:0 range:NSMakeRange(0, rest.length) remainingRange:NULL];
if (!success) return NULL;
memcpy(selector + prefixLength + initialLength + restLength, suffix, suffixLength);
selector[prefixLength + initialLength + restLength + suffixLength] = '\0';
return sel_registerName(selector);
}