mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-10 16:20:42 +00:00
Simplify the KVC getter code and make it return structs boxed in NSValues
(Apple-compatible). This is currently slow, because we go via NSInvocation. We could probably make it faster, but I am not inclined to optimise for something that I sincerely hope is a very unusual use case. Richard: Please check I haven't done something silly here... git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@31411 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
0364f2e365
commit
ec239ebfaf
4 changed files with 102 additions and 373 deletions
|
@ -39,7 +39,7 @@
|
|||
#import "Foundation/NSEnumerator.h"
|
||||
#import "Foundation/NSException.h"
|
||||
#import "Foundation/NSLock.h"
|
||||
#import "Foundation/NSMethodSignature.h"
|
||||
#import "Foundation/NSInvocation.h"
|
||||
#import "Foundation/NSNull.h"
|
||||
#import "Foundation/NSSet.h"
|
||||
#import "Foundation/NSValue.h"
|
||||
|
@ -928,6 +928,11 @@ GSObjCAddClassOverride(Class receiver, Class override)
|
|||
#import "Foundation/NSKeyValueCoding.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Casts the accessor method IMP for sel to the correct type and calls it.
|
||||
*/
|
||||
#define CALL_ACCESSOR(type, self, sel)\
|
||||
(((type (*)(id, SEL))[self methodForSelector: sel])(self, sel))
|
||||
|
||||
/**
|
||||
* This is used internally by the key-value coding methods, to get a
|
||||
|
@ -943,9 +948,13 @@ id
|
|||
GSObjCGetVal(NSObject *self, const char *key, SEL sel,
|
||||
const char *type, unsigned size, int offset)
|
||||
{
|
||||
NSMethodSignature *sig = nil;
|
||||
if (sel != 0)
|
||||
{
|
||||
NSMethodSignature *sig = [self methodSignatureForSelector: sel];
|
||||
// FIXME: This can be slow, because it has to iterate over protocols for
|
||||
// DO calling conventions, which we don't care about here. With
|
||||
// libobjc2, we can skip it and just do a fast slot lookup.
|
||||
sig = [self methodSignatureForSelector: sel];
|
||||
|
||||
if ([sig numberOfArguments] != 2)
|
||||
{
|
||||
|
@ -956,362 +965,74 @@ GSObjCGetVal(NSObject *self, const char *key, SEL sel,
|
|||
}
|
||||
if (type == NULL)
|
||||
{
|
||||
// FIXME: This is stupid - we have an NSString in the caller, then we
|
||||
// extract the buffer, then we create a new NSString.
|
||||
return [self valueForUndefinedKey: [NSString stringWithUTF8String: key]];
|
||||
}
|
||||
else
|
||||
if (0 == sel)
|
||||
{
|
||||
id val = nil;
|
||||
void *addr = ((char *)self + offset);
|
||||
switch (type[0])
|
||||
{
|
||||
// No boxing required for things that are already objects
|
||||
case '@': case '#':
|
||||
return *(id*)addr;
|
||||
// Types not allowed for KVC:
|
||||
case '(': case '^': case '[': case '*': case '?':
|
||||
return [self valueForUndefinedKey: [NSString stringWithUTF8String: key]];
|
||||
// Anything else, we ask NSValue to box for us
|
||||
default:
|
||||
return [NSValue valueWithBytes: addr objCType: type];
|
||||
}
|
||||
}
|
||||
|
||||
// Box a primitive type in an NSNumber and return it
|
||||
switch (*type)
|
||||
{
|
||||
case _C_ID:
|
||||
case _C_CLASS:
|
||||
{
|
||||
id v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(id *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
id (*imp)(id, SEL) =
|
||||
(id (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = v;
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_CHR:
|
||||
{
|
||||
signed char v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(char *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
signed char (*imp)(id, SEL) =
|
||||
(signed char (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithChar: v];
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_UCHR:
|
||||
{
|
||||
unsigned char v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(unsigned char *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char (*imp)(id, SEL) =
|
||||
(unsigned char (*)(id, SEL))[self methodForSelector:
|
||||
sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithUnsignedChar: v];
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_SHT:
|
||||
{
|
||||
short v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(short *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
short (*imp)(id, SEL) =
|
||||
(short (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithShort: v];
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_USHT:
|
||||
{
|
||||
unsigned short v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(unsigned short *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short (*imp)(id, SEL) =
|
||||
(unsigned short (*)(id, SEL))[self methodForSelector:
|
||||
sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithUnsignedShort: v];
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_INT:
|
||||
{
|
||||
int v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(int *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
int (*imp)(id, SEL) =
|
||||
(int (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithInt: v];
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_UINT:
|
||||
{
|
||||
unsigned int v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(unsigned int *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int (*imp)(id, SEL) =
|
||||
(unsigned int (*)(id, SEL))[self methodForSelector:
|
||||
sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithUnsignedInt: v];
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_LNG:
|
||||
{
|
||||
long v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(long *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
long (*imp)(id, SEL) =
|
||||
(long (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithLong: v];
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_ULNG:
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(unsigned long *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long (*imp)(id, SEL) =
|
||||
(unsigned long (*)(id, SEL))[self methodForSelector:
|
||||
sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithUnsignedLong: v];
|
||||
}
|
||||
break;
|
||||
|
||||
#ifdef _C_LNG_LNG
|
||||
case _C_LNG_LNG:
|
||||
{
|
||||
long long v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(long long *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
long long (*imp)(id, SEL) =
|
||||
(long long (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithLongLong: v];
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef _C_ULNG_LNG
|
||||
case _C_ULNG_LNG:
|
||||
{
|
||||
unsigned long long v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(unsigned long long *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long long (*imp)(id, SEL) =
|
||||
(unsigned long long (*)(id, SEL))[self
|
||||
methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithUnsignedLongLong: v];
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case _C_FLT:
|
||||
{
|
||||
float v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(float *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
float (*imp)(id, SEL) =
|
||||
(float (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithFloat: v];
|
||||
}
|
||||
break;
|
||||
|
||||
case _C_DBL:
|
||||
{
|
||||
double v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
v = *(double *)((char *)self + offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
double (*imp)(id, SEL) =
|
||||
(double (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSNumber numberWithDouble: v];
|
||||
}
|
||||
break;
|
||||
|
||||
return [self methodForSelector: sel](self, sel);
|
||||
#define INTEGER_MACRO(encoding, type, name, capitalizedName) \
|
||||
case encoding: \
|
||||
return [NSNumber numberWith ## capitalizedName: CALL_ACCESSOR(type, self, sel)];
|
||||
#define NO_NSNUMBER 1
|
||||
#include "../GSNumberTypes.h"
|
||||
case _C_VOID:
|
||||
{
|
||||
void (*imp)(id, SEL) =
|
||||
(void (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
(*imp)(self, sel);
|
||||
}
|
||||
val = nil;
|
||||
break;
|
||||
// Calling an accessor method that doesn't return anything is crazy,
|
||||
// but it's Apple-compatible crazy.
|
||||
CALL_ACCESSOR(void, self, sel);
|
||||
return nil;
|
||||
|
||||
case _C_STRUCT_B:
|
||||
if (strcmp(@encode(NSPoint), type) == 0)
|
||||
{
|
||||
NSPoint v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
memcpy((char*)&v, ((char *)self + offset), sizeof(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
NSPoint (*imp)(id, SEL) =
|
||||
(NSPoint (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSValue valueWithPoint: v];
|
||||
return [NSValue valueWithPoint: CALL_ACCESSOR(NSPoint, self, sel)];
|
||||
}
|
||||
else if (strcmp(@encode(NSRange), type) == 0)
|
||||
{
|
||||
NSRange v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
memcpy((char*)&v, ((char *)self + offset), sizeof(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
NSRange (*imp)(id, SEL) =
|
||||
(NSRange (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSValue valueWithRange: v];
|
||||
return [NSValue valueWithRange: CALL_ACCESSOR(NSRange, self, sel)];
|
||||
}
|
||||
else if (strcmp(@encode(NSRect), type) == 0)
|
||||
{
|
||||
NSRect v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
memcpy((char*)&v, ((char *)self + offset), sizeof(v));
|
||||
}
|
||||
else
|
||||
{
|
||||
NSRect (*imp)(id, SEL) =
|
||||
(NSRect (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSValue valueWithRect: v];
|
||||
return [NSValue valueWithRect: CALL_ACCESSOR(NSRect, self, sel)];
|
||||
}
|
||||
else if (strcmp(@encode(NSSize), type) == 0)
|
||||
{
|
||||
NSSize v;
|
||||
|
||||
if (sel == 0)
|
||||
{
|
||||
memcpy((char*)&v, ((char *)self + offset), sizeof(v));
|
||||
return [NSValue valueWithSize: CALL_ACCESSOR(NSSize, self, sel)];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSSize (*imp)(id, SEL) =
|
||||
(NSSize (*)(id, SEL))[self methodForSelector: sel];
|
||||
|
||||
v = (*imp)(self, sel);
|
||||
}
|
||||
val = [NSValue valueWithSize: v];
|
||||
}
|
||||
else
|
||||
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sig];
|
||||
[inv invokeWithTarget: self];
|
||||
{
|
||||
val = [self valueForUndefinedKey:
|
||||
[NSString stringWithUTF8String: key]];
|
||||
size_t retSize = [sig methodReturnLength];
|
||||
char ret[retSize];
|
||||
[inv getReturnValue: ret];
|
||||
return [NSValue valueWithBytes: ret objCType: type];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
val = [self valueForUndefinedKey:
|
||||
[NSString stringWithUTF8String: key]];
|
||||
}
|
||||
return val;
|
||||
return [self valueForUndefinedKey: [NSString stringWithUTF8String: key]];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,20 +7,28 @@
|
|||
*
|
||||
*/
|
||||
#ifndef INTEGER_MACRO
|
||||
#error Define INTEGER_MACRO(type, name, capitalizedName) before including GSNumberTypes.h
|
||||
#error Define INTEGER_MACRO(encoding, type, name, capitalizedName) before including GSNumberTypes.h
|
||||
#endif
|
||||
INTEGER_MACRO(double, double, Double)
|
||||
INTEGER_MACRO(float, float, Float)
|
||||
INTEGER_MACRO(signed char, char, Char)
|
||||
INTEGER_MACRO(int, int, Int)
|
||||
INTEGER_MACRO(short, short, Short)
|
||||
INTEGER_MACRO(long, long, Long)
|
||||
INTEGER_MACRO(NSInteger, integer, Integer)
|
||||
INTEGER_MACRO(NSUInteger, unsignedInteger, UnsignedInteger)
|
||||
INTEGER_MACRO(long long, longLong, LongLong)
|
||||
INTEGER_MACRO(unsigned char, unsignedChar, UnsignedChar)
|
||||
INTEGER_MACRO(unsigned short, unsignedShort, UnsignedShort)
|
||||
INTEGER_MACRO(unsigned int, unsignedInt, UnsignedInt)
|
||||
INTEGER_MACRO(unsigned long, unsignedLong, UnsignedLong)
|
||||
INTEGER_MACRO(unsigned long long, unsignedLongLong, UnsignedLongLong)
|
||||
INTEGER_MACRO('d', double, double, Double)
|
||||
INTEGER_MACRO('f', float, float, Float)
|
||||
INTEGER_MACRO('c', signed char, char, Char)
|
||||
INTEGER_MACRO('i', int, int, Int)
|
||||
INTEGER_MACRO('s', short, short, Short)
|
||||
INTEGER_MACRO('l', long, long, Long)
|
||||
#ifndef NO_NSNUMBER
|
||||
# if SIZEOF_VOIDP == 4
|
||||
INTEGER_MACRO('i', NSInteger, integer, Integer)
|
||||
INTEGER_MACRO('I', NSUInteger, unsignedInteger, UnsignedInteger)
|
||||
# undef NO_NSNUMBER
|
||||
# else
|
||||
INTEGER_MACRO('q', NSInteger, integer, Integer)
|
||||
INTEGER_MACRO('Q', NSUInteger, unsignedInteger, UnsignedInteger)
|
||||
# endif
|
||||
#endif
|
||||
INTEGER_MACRO('q', long long, longLong, LongLong)
|
||||
INTEGER_MACRO('C', unsigned char, unsignedChar, UnsignedChar)
|
||||
INTEGER_MACRO('S', unsigned short, unsignedShort, UnsignedShort)
|
||||
INTEGER_MACRO('I', unsigned int, unsignedInt, UnsignedInt)
|
||||
INTEGER_MACRO('L', unsigned long, unsignedLong, UnsignedLong)
|
||||
INTEGER_MACRO('Q', unsigned long long, unsignedLongLong, UnsignedLongLong)
|
||||
#undef INTEGER_MACRO
|
||||
|
|
|
@ -411,7 +411,7 @@ static NSBoolNumber *boolN; // Boolean NO (integer 0)
|
|||
return 0; // Not reached
|
||||
}
|
||||
|
||||
#define INTEGER_MACRO(type, ignored, name) \
|
||||
#define INTEGER_MACRO(encoding,type, ignored, name) \
|
||||
- (id) initWith ## name: (type)aValue \
|
||||
{\
|
||||
DESTROY(self);\
|
||||
|
@ -735,7 +735,7 @@ if (aValue >= -1 && aValue <= 12)\
|
|||
* exception here matches OS X behaviour, although they throw an invalid
|
||||
* argument exception.
|
||||
*/
|
||||
#define INTEGER_MACRO(type, name, ignored) \
|
||||
#define INTEGER_MACRO(encoding, type, name, ignored) \
|
||||
- (type) name ## Value\
|
||||
{\
|
||||
[self subclassResponsibility: _cmd];\
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define INTEGER_MACRO(type, name, ignored) \
|
||||
#define INTEGER_MACRO(encoding, type, name, ignored) \
|
||||
- (type) name ## Value\
|
||||
{\
|
||||
return (type)VALUE;\
|
||||
|
|
Loading…
Reference in a new issue