NSKeyValueCoding: Safe-Caching for -[NSObject valueForKey:] (#445)

* KVC Caching Implementation

* Do not ignore struct name when comparing type encoding as NSPoint and NSSize have the same layout

* Use fast-path when using Objective-C 2

* Guard old ValueForKey function when using the fast-path

* Add basic NSKeyValueCoding tests

* Update Copyright Years

* NSKeyValueCoding+Caching: Add Versioning to IVar Slot

* safe_caching: Remove Guards

* Add type encoding helper header

* Rename geometry structs (NSRect, NSPoint, NSSize) for toll-free bridging with CoreGraphics

* Move CG struct definitions to CFCGTypes.h

* Update known struct encoding prefixes

* Windows 64-bit is LLP64 and not LP64

* Re-order to avoid complier warning

---------

Co-authored-by: rfm <richardfrithmacdonald@gmail.com>
This commit is contained in:
Hugo Melder 2024-10-29 06:12:34 -07:00 committed by GitHub
parent 4f0a8d60c2
commit 6eef1c3289
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 1549 additions and 49 deletions

View file

@ -41,6 +41,9 @@
#include "NSKeyValueMutableArray.m"
#include "NSKeyValueMutableSet.m"
#if defined(__OBJC2__)
#import "NSKeyValueCoding+Caching.h"
#endif
/* this should move into autoconf once it's accepted */
#define WANT_DEPRECATED_KVC_COMPAT 1
@ -144,6 +147,7 @@ SetValueForKey(NSObject *self, id anObject, const char *key, unsigned size)
GSObjCSetVal(self, key, anObject, sel, type, size, off);
}
#if !defined(__OBJC2__)
static id ValueForKey(NSObject *self, const char *key, unsigned size)
{
SEL sel = 0;
@ -166,12 +170,12 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
name = &buf[1]; // getKey
sel = sel_getUid(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
if ([self respondsToSelector: sel] == NO)
{
buf[4] = lo;
name = &buf[4]; // key
sel = sel_getUid(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
if ([self respondsToSelector: sel] == NO)
{
buf[4] = hi;
buf[3] = 's';
@ -190,13 +194,13 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
buf[4] = hi;
name = buf; // _getKey
sel = sel_getUid(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
if ([self respondsToSelector: sel] == NO)
{
buf[4] = lo;
buf[3] = '_';
name = &buf[3]; // _key
sel = sel_getUid(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
if ([self respondsToSelector: sel] == NO)
{
sel = 0;
}
@ -229,6 +233,7 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
}
return GSObjCGetVal(self, key, sel, type, size, off);
}
#endif
@implementation NSObject(KeyValueCoding)
@ -513,6 +518,9 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
- (id) valueForKey: (NSString*)aKey
{
#if defined(__OBJC2__)
return valueForKeyWithCaching(self, aKey);
#else
unsigned size = [aKey length] * 8;
char key[size + 1];
@ -521,6 +529,7 @@ static id ValueForKey(NSObject *self, const char *key, unsigned size)
encoding: NSUTF8StringEncoding];
size = strlen(key);
return ValueForKey(self, key, size);
#endif
}