-
Notifications
You must be signed in to change notification settings - Fork 282
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]>
- Loading branch information
Showing
37 changed files
with
1,549 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/** CFCGTypes.h - CoreFoundation header file for CG types | ||
Copyright (C) 2024 Free Software Foundation, Inc. | ||
Written by: Hugo Melder <[email protected]> | ||
Created: October 2024 | ||
This file is part of the GNUstep Base Library. | ||
This library is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU Lesser General Public | ||
License as published by the Free Software Foundation; either | ||
version 2 of the License, or (at your option) any later version. | ||
This library is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
Lesser General Public License for more details. | ||
You should have received a copy of the GNU Lesser General Public | ||
License along with this library; if not, write to the Free | ||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
Boston, MA 02110 USA. | ||
*/ | ||
|
||
#ifndef _CFCGTypes_h_GNUSTEP_BASE_INCLUDE | ||
#define _CFCGTypes_h_GNUSTEP_BASE_INCLUDE | ||
|
||
#include <float.h> | ||
#include <stdint.h> | ||
|
||
#define CF_DEFINES_CG_TYPES | ||
|
||
#if defined(__has_attribute) && __has_attribute(objc_boxable) | ||
# define CF_BOXABLE __attribute__((objc_boxable)) | ||
#else | ||
# define CF_BOXABLE | ||
#endif | ||
|
||
#if (defined(__LP64__) && __LP64__) || defined(_WIN64) | ||
# define CGFLOAT_TYPE double | ||
# define CGFLOAT_IS_DOUBLE 1 | ||
# define CGFLOAT_MIN DBL_MIN | ||
# define CGFLOAT_MAX DBL_MAX | ||
# define CGFLOAT_EPSILON DBL_EPSILON | ||
#else | ||
# define CGFLOAT_TYPE float | ||
# define CGFLOAT_IS_DOUBLE 0 | ||
# define CGFLOAT_MIN FLT_MIN | ||
# define CGFLOAT_MAX FLT_MAX | ||
# define CGFLOAT_EPSILON FLT_EPSILON | ||
#endif | ||
|
||
typedef CGFLOAT_TYPE CGFloat; | ||
#define CGFLOAT_DEFINED 1 | ||
|
||
struct | ||
CGPoint { | ||
CGFloat x; | ||
CGFloat y; | ||
}; | ||
typedef struct CF_BOXABLE CGPoint CGPoint; | ||
|
||
struct CGSize { | ||
CGFloat width; | ||
CGFloat height; | ||
}; | ||
typedef struct CF_BOXABLE CGSize CGSize; | ||
|
||
#define CGVECTOR_DEFINED 1 | ||
|
||
struct CGVector { | ||
CGFloat dx; | ||
CGFloat dy; | ||
}; | ||
typedef struct CF_BOXABLE CGVector CGVector; | ||
|
||
struct CGRect { | ||
CGPoint origin; | ||
CGSize size; | ||
}; | ||
typedef struct CF_BOXABLE CGRect CGRect; | ||
|
||
enum | ||
{ | ||
CGRectMinXEdge = 0, | ||
CGRectMinYEdge = 1, | ||
CGRectMaxXEdge = 2, | ||
CGRectMaxYEdge = 3 | ||
}; | ||
|
||
typedef struct CGAffineTransform CGAffineTransform; | ||
|
||
struct CGAffineTransform { | ||
CGFloat a, b, c, d; | ||
CGFloat tx, ty; | ||
}; | ||
|
||
#define CF_DEFINES_CGAFFINETRANSFORMCOMPONENTS | ||
|
||
/* |------------------ CGAffineTransformComponents ----------------| | ||
* | ||
* | a b 0 | | sx 0 0 | | 1 0 0 | | cos(t) sin(t) 0 | | 1 0 0 | | ||
* | c d 0 | = | 0 sy 0 | * | sh 1 0 | * |-sin(t) cos(t) 0 | * | 0 1 0 | | ||
* | tx ty 1 | | 0 0 1 | | 0 0 1 | | 0 0 1 | | tx ty 1 | | ||
* CGAffineTransform scale shear rotation translation | ||
*/ | ||
typedef struct CGAffineTransformComponents CGAffineTransformComponents; | ||
|
||
struct CGAffineTransformComponents { | ||
|
||
/* Scale factors in X and Y dimensions. Negative values indicate flipping along that axis. */ | ||
CGSize scale; | ||
|
||
/* Shear distortion along the horizontal axis. A value of 0 means no shear. */ | ||
CGFloat horizontalShear; | ||
|
||
/* Rotation angle in radians around the origin. Sign convention may vary | ||
* based on the coordinate system used. */ | ||
CGFloat rotation; | ||
|
||
/* Translation or displacement along the X and Y axes. */ | ||
CGVector translation; | ||
}; | ||
|
||
|
||
#endif // _CFCGTypes_h_GNUSTEP_BASE_INCLUDE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/** Key-Value Coding Safe Caching Support | ||
Copyright (C) 2024 Free Software Foundation, Inc. | ||
Written by: Hugo Melder <[email protected]> | ||
Created: August 2024 | ||
This file is part of the GNUstep Base Library. | ||
This library is free software; you can redistribute it and/or | ||
modify it under the terms of the GNU Lesser General Public | ||
License as published by the Free Software Foundation; either | ||
version 2 of the License, or (at your option) any later version. | ||
This library is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
Lesser General Public License for more details. | ||
You should have received a copy of the GNU Lesser General Public | ||
License along with this library; if not, write to the Free | ||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
Boston, MA 02110 USA. | ||
*/ | ||
|
||
/** | ||
* It turns out that valueForKey: is a very expensive operation, and a major | ||
* bottleneck for Key-Value Observing and other operations such as sorting | ||
* an array by key. | ||
* | ||
* The accessor search patterns for Key-Value observing are discussed in the | ||
* Apple Key-Value Coding Programming Guide. The return value may be | ||
* encapuslated into an NSNumber or NSValue object, depending on the Objective-C | ||
* type encoding of the return value. This means that once valueForKey: found an | ||
* existing accessor, the Objective-C type encoding of the accessor is | ||
* retrieved. We then go through a huge switch case to determine the right way | ||
* to invoke the IMP and potentially encapsulate the return type. The resulting | ||
* object is then returned. | ||
* The algorithm for setValue:ForKey: is similar. | ||
* | ||
* We can speed this up by caching the IMP of the accessor in a hash table. | ||
* However, without proper versioning, this quickly becomes very dangerous. | ||
* The user might exchange implementations, or add new ones expecting the | ||
* search pattern invariant to still hold. If we clamp onto an IMP, this | ||
* invariant no longer holds. | ||
* | ||
* We will make use of libobjc2's safe caching to avoid this. | ||
* | ||
* Note that the caching is opaque. You will only need to redirect all | ||
* valueForKey: calls to the function below. | ||
*/ | ||
|
||
#import "Foundation/NSString.h" | ||
|
||
id | ||
valueForKeyWithCaching(id obj, NSString *aKey); |
Oops, something went wrong.