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:
rfm 2012-07-27 16:48:49 +00:00
parent 52dbdbcf0e
commit e357aab701
8 changed files with 156 additions and 45 deletions

View file

@ -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

View file

@ -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__))

View file

@ -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

View file

@ -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;

View file

@ -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:

View file

@ -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,

View file

@ -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

View file

@ -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;