mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
crude KVO setter for structs
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@35324 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
52dbdbcf0e
commit
e357aab701
8 changed files with 156 additions and 45 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
2012-07-27 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSKeyValueObserving.m:
|
||||
* Source/GSFFIInvocation.m:
|
||||
* Source/GSPrivate.h:
|
||||
* Source/NSInvocation.m:
|
||||
* Source/cifframe.h:
|
||||
* Source/cifframe.m:
|
||||
Initial attempt at implementing KVO for structure setter methods in
|
||||
general via libffi.
|
||||
|
||||
2012-07-27 Fred Kiefer <FredKiefer@gmx.de>
|
||||
|
||||
* Source/NSXMLNode.m (-description): Remove trailing newline. This
|
||||
|
|
|
@ -145,10 +145,6 @@ gs_find_best_typed_sel (SEL sel)
|
|||
|
||||
static IMP gs_objc_msg_forward2 (id receiver, SEL sel)
|
||||
{
|
||||
NSMutableData *frame;
|
||||
cifframe_t *cframe;
|
||||
ffi_closure *cclosure;
|
||||
void *executable;
|
||||
NSMethodSignature *sig = nil;
|
||||
GSCodeBuffer *memory;
|
||||
const char *types;
|
||||
|
@ -206,38 +202,9 @@ static IMP gs_objc_msg_forward2 (id receiver, SEL sel)
|
|||
}
|
||||
}
|
||||
|
||||
/* Construct the frame and closure. */
|
||||
/* Note: We obtain cframe here, but it's passed to GSFFIInvocationCallback
|
||||
where it becomes owned by the callback invocation, so we don't have to
|
||||
worry about ownership */
|
||||
frame = cifframe_from_signature(sig);
|
||||
cframe = [frame mutableBytes];
|
||||
/* Autorelease the closure through GSAutoreleasedBuffer */
|
||||
memory = cifframe_closure(sig, GSFFIInvocationCallback);
|
||||
|
||||
memory = [GSCodeBuffer memoryWithSize: sizeof(ffi_closure)];
|
||||
cclosure = [memory buffer];
|
||||
executable = [memory executable];
|
||||
if (cframe == NULL || cclosure == NULL)
|
||||
{
|
||||
[NSException raise: NSMallocException format: @"Allocating closure"];
|
||||
}
|
||||
#if HAVE_FFI_PREP_CLOSURE_LOC
|
||||
if (ffi_prep_closure_loc(cclosure, &(cframe->cif),
|
||||
GSFFIInvocationCallback, frame, executable) != FFI_OK)
|
||||
{
|
||||
[NSException raise: NSGenericException format: @"Preping closure"];
|
||||
}
|
||||
#else
|
||||
executable = (void*)cclosure;
|
||||
if (ffi_prep_closure(cclosure, &(cframe->cif),
|
||||
GSFFIInvocationCallback, frame) != FFI_OK)
|
||||
{
|
||||
[NSException raise: NSGenericException format: @"Preping closure"];
|
||||
}
|
||||
#endif
|
||||
[memory protect];
|
||||
|
||||
return (IMP)executable;
|
||||
return (IMP)[memory executable];
|
||||
}
|
||||
|
||||
static __attribute__ ((__unused__))
|
||||
|
|
|
@ -527,12 +527,14 @@ GSPrivateUnloadModule(FILE *errorStream,
|
|||
unsigned size;
|
||||
void *buffer;
|
||||
void *executable;
|
||||
id frame;
|
||||
}
|
||||
+ (GSCodeBuffer*) memoryWithSize: (NSUInteger)_size;
|
||||
- (void*) buffer;
|
||||
- (void*) executable;
|
||||
- (id) initWithSize: (NSUInteger)_size;
|
||||
- (void) protect;
|
||||
- (void) setFrame: (id)aFrame;
|
||||
@end
|
||||
|
||||
BOOL
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
DESTROY(frame);
|
||||
if (size > 0)
|
||||
{
|
||||
#if defined(HAVE_FFI_PREP_CLOSURE_LOC)
|
||||
|
@ -173,6 +174,11 @@
|
|||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void) setFrame: (id)aFrame
|
||||
{
|
||||
ASSIGN(frame, aFrame);
|
||||
}
|
||||
@end
|
||||
|
||||
static Class NSInvocation_abstract_class;
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
#import "GNUstepBase/NSObject+GNUstepBase.h"
|
||||
#import "GSInvocation.h"
|
||||
|
||||
#if defined(USE_LIBFFI)
|
||||
#import "cifframe.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* IMPLEMENTATION NOTES
|
||||
*
|
||||
|
@ -385,6 +389,38 @@ replacementForClass(Class c)
|
|||
return r;
|
||||
}
|
||||
|
||||
#if defined(USE_LIBFFI)
|
||||
static void
|
||||
cifframe_callback(ffi_cif *cif, void *retp, void **args, void *user)
|
||||
{
|
||||
id obj;
|
||||
SEL sel;
|
||||
NSString *key;
|
||||
Class c;
|
||||
void (*imp)(id,SEL,void*);
|
||||
|
||||
obj = *(id *)args[0];
|
||||
sel = *(SEL *)args[1];
|
||||
c = [obj class];
|
||||
|
||||
imp = (void (*)(id,SEL,void*))[c instanceMethodForSelector: sel];
|
||||
key = newKey(sel);
|
||||
if ([c automaticallyNotifiesObserversForKey: key] == YES)
|
||||
{
|
||||
// pre setting code here
|
||||
[obj willChangeValueForKey: key];
|
||||
ffi_call(cif, imp, retp, args);
|
||||
// post setting code here
|
||||
[obj didChangeValueForKey: key];
|
||||
}
|
||||
else
|
||||
{
|
||||
ffi_call(cif, imp, retp, args);
|
||||
}
|
||||
RELEASE(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
@implementation GSKVOReplacement
|
||||
- (void) dealloc
|
||||
{
|
||||
|
@ -557,7 +593,15 @@ replacementForClass(Class c)
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined(USE_LIBFFI)
|
||||
GSCodeBuffer *b;
|
||||
|
||||
b = cifframe_closure(sig, cifframe_callback);
|
||||
[b retain];
|
||||
imp = [b executable];
|
||||
#else
|
||||
imp = 0;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -40,8 +40,9 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "Foundation/NSMethodSignature.h"
|
||||
#include "GNUstepBase/DistributedObjects.h"
|
||||
#import "Foundation/NSMethodSignature.h"
|
||||
#import "GNUstepBase/DistributedObjects.h"
|
||||
#import "GSPrivate.h"
|
||||
|
||||
typedef struct _cifframe_t {
|
||||
ffi_cif cif;
|
||||
|
@ -54,6 +55,8 @@ typedef struct _cifframe_t {
|
|||
|
||||
extern NSMutableData *cifframe_from_signature (NSMethodSignature *info);
|
||||
|
||||
extern GSCodeBuffer* cifframe_closure (NSMethodSignature *sig, void (*func)());
|
||||
|
||||
extern void cifframe_set_arg(cifframe_t *cframe, int index, void *buffer,
|
||||
int size);
|
||||
extern void cifframe_get_arg(cifframe_t *cframe, int index, void *buffer,
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#import "Foundation/NSException.h"
|
||||
#import "Foundation/NSData.h"
|
||||
#import "GSInvocation.h"
|
||||
#import "GSPrivate.h"
|
||||
|
||||
#if defined(ALPHA) || (defined(MIPS) && (_MIPS_SIM == _ABIN32))
|
||||
typedef long long smallret_t;
|
||||
|
@ -529,6 +530,46 @@ cifframe_type(const char *typePtr, const char **advance)
|
|||
return ftype;
|
||||
}
|
||||
|
||||
GSCodeBuffer*
|
||||
cifframe_closure (NSMethodSignature *sig, void (*cb)())
|
||||
{
|
||||
NSMutableData *frame;
|
||||
cifframe_t *cframe;
|
||||
ffi_closure *cclosure;
|
||||
void *executable;
|
||||
GSCodeBuffer *memory;
|
||||
|
||||
/* Construct the frame (stored in an NSMutableDate object) and sety it
|
||||
* in a new closure.
|
||||
*/
|
||||
frame = cifframe_from_signature(sig);
|
||||
cframe = [frame mutableBytes];
|
||||
memory = [GSCodeBuffer memoryWithSize: sizeof(ffi_closure)];
|
||||
[memory setFrame: frame];
|
||||
cclosure = [memory buffer];
|
||||
executable = [memory executable];
|
||||
if (cframe == NULL || cclosure == NULL)
|
||||
{
|
||||
[NSException raise: NSMallocException format: @"Allocating closure"];
|
||||
}
|
||||
#if HAVE_FFI_PREP_CLOSURE_LOC
|
||||
if (ffi_prep_closure_loc(cclosure, &(cframe->cif),
|
||||
cb, frame, executable) != FFI_OK)
|
||||
{
|
||||
[NSException raise: NSGenericException format: @"Preping closure"];
|
||||
}
|
||||
#else
|
||||
executable = (void*)cclosure;
|
||||
if (ffi_prep_closure(cclosure, &(cframe->cif),
|
||||
cb, frame) != FFI_OK)
|
||||
{
|
||||
[NSException raise: NSGenericException format: @"Preping closure"];
|
||||
}
|
||||
#endif
|
||||
[memory protect];
|
||||
return memory;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Functions for handling sending and receiving messages accross a
|
||||
connection
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
#import "ObjectTesting.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
float b;
|
||||
char *c;
|
||||
} aStruct;
|
||||
|
||||
@interface Observer : NSObject
|
||||
- (void) observeValueForKeyPath: (NSString *)keyPath
|
||||
ofObject: (id)object
|
||||
|
@ -25,14 +31,33 @@
|
|||
NSMutableArray * numbers;
|
||||
NSMutableArray * third;
|
||||
NSString *string;
|
||||
aStruct x;
|
||||
}
|
||||
|
||||
- (int) a;
|
||||
- (float) b;
|
||||
- (const char*) c;
|
||||
@end
|
||||
|
||||
|
||||
@implementation Lists
|
||||
|
||||
- (id)init
|
||||
- (int) a
|
||||
{
|
||||
return x.a;
|
||||
}
|
||||
|
||||
- (float) b
|
||||
{
|
||||
return x.b;
|
||||
}
|
||||
|
||||
- (const char*) c
|
||||
{
|
||||
return x.c;
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
cities = [[NSMutableArray alloc] initWithObjects:
|
||||
@"Grand Rapids",
|
||||
|
@ -53,7 +78,7 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)obj inNumbersAtIndex:(unsigned int)index
|
||||
- (void) insertObject:(id)obj inNumbersAtIndex:(unsigned int)index
|
||||
{
|
||||
if (![obj isEqualToString:@"NaN"])
|
||||
{
|
||||
|
@ -61,20 +86,20 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)removeObjectFromNumbersAtIndex:(unsigned int)index
|
||||
- (void) removeObjectFromNumbersAtIndex:(unsigned int)index
|
||||
{
|
||||
if (![[numbers objectAtIndex:index] isEqualToString:@"One"])
|
||||
[numbers removeObjectAtIndex:index];
|
||||
}
|
||||
|
||||
- (void)replaceObjectInNumbersAtIndex:(unsigned int)index withObject:(id)obj
|
||||
- (void) replaceObjectInNumbersAtIndex:(unsigned int)index withObject:(id)obj
|
||||
{
|
||||
if (index == 1)
|
||||
obj = @"Two";
|
||||
[numbers replaceObjectAtIndex:index withObject:obj];
|
||||
}
|
||||
|
||||
- (void)setCities:(NSArray *)other
|
||||
- (void) setCities:(NSArray *)other
|
||||
{
|
||||
[cities setArray:other];
|
||||
}
|
||||
|
@ -85,6 +110,11 @@
|
|||
[super didChangeValueForKey: k];
|
||||
}
|
||||
|
||||
- (void) setX: (aStruct)s
|
||||
{
|
||||
x = s;
|
||||
}
|
||||
|
||||
- (void) willChangeValueForKey: (NSString*)k
|
||||
{
|
||||
[super willChangeValueForKey: k];
|
||||
|
@ -117,13 +147,13 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)addOneObject:(id)anObject
|
||||
- (void) addOneObject:(id)anObject
|
||||
{
|
||||
if (![anObject isEqualToString:@"ten"])
|
||||
[one addObject:anObject];
|
||||
}
|
||||
|
||||
- (void)removeOneObject:(id)anObject
|
||||
- (void) removeOneObject:(id)anObject
|
||||
{
|
||||
if (![anObject isEqualToString:@"one"])
|
||||
{
|
||||
|
@ -131,7 +161,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)setTwo:(NSMutableSet *)set
|
||||
- (void) setTwo:(NSMutableSet *)set
|
||||
{
|
||||
[two setSet:set];
|
||||
}
|
||||
|
@ -144,12 +174,14 @@ int main(void)
|
|||
|
||||
Lists *list = [[[Lists alloc] init] autorelease];
|
||||
Observer *observer = [Observer new];
|
||||
aStruct s = {1, 2, "3" };
|
||||
id o;
|
||||
NSMutableArray * proxy;
|
||||
NSDictionary * temp;
|
||||
|
||||
[list addObserver: observer forKeyPath: @"numbers" options: 15 context: 0];
|
||||
[list addObserver: observer forKeyPath: @"string" options: 15 context: 0];
|
||||
[list addObserver: observer forKeyPath: @"x" options: 15 context: 0];
|
||||
|
||||
[list setValue: @"x" forKey: @"string"];
|
||||
|
||||
|
@ -239,8 +271,13 @@ int main(void)
|
|||
PASS([setProxy isKindOfClass:NSClassFromString(@"NSKeyValueMutableSet")],
|
||||
"mutableSetValueForKey: works")
|
||||
|
||||
[list setX: s];
|
||||
PASS([list a] == 1 && [list b] == 2.0 && strcmp([list c], "3") == 0,
|
||||
"able to set struct");
|
||||
|
||||
[list removeObserver: observer forKeyPath: @"numbers"];
|
||||
[list removeObserver: observer forKeyPath: @"string"];
|
||||
[list removeObserver: observer forKeyPath: @"x"];
|
||||
|
||||
[arp release]; arp = nil;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue