key-value coding fixes

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@8246 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2000-12-02 21:36:56 +00:00
parent a1d9d92494
commit c78a6ca413
4 changed files with 624 additions and 146 deletions

View file

@ -3,8 +3,8 @@
* Source/NSDate.m: GSTime() added millisecond info. * Source/NSDate.m: GSTime() added millisecond info.
* Source/NSCalendarDate.m: GSTime() added millisecond info. * Source/NSCalendarDate.m: GSTime() added millisecond info.
* Headers/Foundation/NSDate.h: GSTime() added millisecond info. * Headers/Foundation/NSDate.h: GSTime() added millisecond info.
* Source/NSObject.m: key-value-coding restructured to simplify * Source/NSObject.m: key-value-coding restructured and
future implementation for non-object values. implemented for non-object values.
2000-11-30 Richard Frith-Macdonald <rfm@gnu.org> 2000-11-30 Richard Frith-Macdonald <rfm@gnu.org>

View file

@ -77,8 +77,9 @@ GS_EXPORT void NSLogv (NSString* format, va_list args);
* Get the type encoding for a named ivar, * Get the type encoding for a named ivar,
* and copy a value into an ivar. * and copy a value into an ivar.
*/ */
GS_EXPORT BOOL GSInstanceVariableInfo(id obj, NSString *iVarName,
const char **type, unsigned *size, unsigned *offset);
GS_EXPORT BOOL GSGetInstanceVariable(id obj, NSString *name, void* data); GS_EXPORT BOOL GSGetInstanceVariable(id obj, NSString *name, void* data);
GS_EXPORT const char *GSInstanceVariableType(id obj, NSString *name);
GS_EXPORT BOOL GSSetInstanceVariable(id obj, NSString *name, const void* data); GS_EXPORT BOOL GSSetInstanceVariable(id obj, NSString *name, const void* data);
/* /*

View file

@ -70,17 +70,15 @@ NSGetSizeAndAlignment(const char *typePtr, unsigned *sizep, unsigned *alignp)
*alignp = info.align; *alignp = info.align;
return typePtr; return typePtr;
} }
BOOL BOOL
GSGetInstanceVariable(id obj, NSString *iVarName, void *data) GSInstanceVariableInfo(id obj, NSString *iVarName,
const char **type, unsigned *size, unsigned *offset)
{ {
const char *name = [iVarName cString]; const char *name = [iVarName cString];
Class class; Class class;
struct objc_ivar_list *ivars; struct objc_ivar_list *ivars;
struct objc_ivar *ivar = 0; struct objc_ivar *ivar = 0;
int offset;
const char *type;
unsigned int size;
class = [obj class]; class = [obj class];
while (class != nil && ivar == 0) while (class != nil && ivar == 0)
@ -106,86 +104,42 @@ GSGetInstanceVariable(id obj, NSString *iVarName, void *data)
return NO; return NO;
} }
offset = ivar->ivar_offset; if (*type)
type = ivar->ivar_type; *type = ivar->ivar_type;
size = objc_sizeof_type(type); if (*size)
memcpy(data, ((void*)obj) + offset, size); *size = objc_sizeof_type(ivar->ivar_type);
if (*offset)
*offset = ivar->ivar_offset;
return YES; return YES;
} }
const char* BOOL
GSInstanceVariableType(id obj, NSString *iVarName) GSGetInstanceVariable(id obj, NSString *iVarName, void *data)
{ {
const char *name = [iVarName cString]; int offset;
Class class; const char *type;
struct objc_ivar_list *ivars; unsigned int size;
struct objc_ivar *ivar = 0;
class = [obj class]; if (GSInstanceVariableInfo(obj, iVarName, &type, &size, &offset) == NO)
while (class != nil && ivar == 0)
{ {
ivars = class->ivars; return NO;
class = class->super_class;
if (ivars != 0)
{
int i;
for (i = 0; i < ivars->ivar_count; i++)
{
if (strcmp(ivars->ivar_list[i].ivar_name, name) == 0)
{
ivar = &ivars->ivar_list[i];
break;
}
}
}
}
if (ivar == 0)
{
return 0;
} }
return ivar->ivar_type; memcpy(data, ((void*)obj) + offset, size);
return YES;
} }
BOOL BOOL
GSSetInstanceVariable(id obj, NSString *iVarName, const void *data) GSSetInstanceVariable(id obj, NSString *iVarName, const void *data)
{ {
const char *name = [iVarName cString];
Class class;
struct objc_ivar_list *ivars;
struct objc_ivar *ivar = 0;
int offset; int offset;
const char *type; const char *type;
unsigned int size; unsigned int size;
class = [obj class]; if (GSInstanceVariableInfo(obj, iVarName, &type, &size, &offset) == NO)
while (class != nil && ivar == 0)
{
ivars = class->ivars;
class = class->super_class;
if (ivars != 0)
{
int i;
for (i = 0; i < ivars->ivar_count; i++)
{
if (strcmp(ivars->ivar_list[i].ivar_name, name) == 0)
{
ivar = &ivars->ivar_list[i];
break;
}
}
}
}
if (ivar == 0)
{ {
return NO; return NO;
} }
offset = ivar->ivar_offset;
type = ivar->ivar_type;
size = objc_sizeof_type(type);
memcpy(((void*)obj) + offset, data, size); memcpy(((void*)obj) + offset, data, size);
return YES; return YES;
} }

View file

@ -1277,12 +1277,578 @@ static BOOL deallocNotifications = NO;
#include <Foundation/NSValue.h>
#include <Foundation/NSKeyValueCoding.h> #include <Foundation/NSKeyValueCoding.h>
#include <Foundation/NSNull.h> #include <Foundation/NSNull.h>
@implementation NSObject (KeyValueCoding) @implementation NSObject (KeyValueCoding)
static id
GSGetValue(NSObject *self, NSString *key, SEL sel,
const char *type, unsigned size, unsigned off)
{
if (sel != 0)
{
NSMethodSignature *sig = [self methodSignatureForSelector: sel];
if ([sig numberOfArguments] != 2)
{
[NSException raise: NSInvalidArgumentException
format: @"key-value set method has wrong number of args"];
}
type = [sig methodReturnType];
}
if (type == 0)
{
[self handleTakeValue: nil forUnboundKey: key];
return nil;
}
else
{
id val;
switch (*type)
{
case _C_ID:
case _C_CLASS:
{
id v;
if (sel == 0)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
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)
{
memcpy((void*)&v, ((void*)self) + off, size);
}
else
{
double (*imp)(id, SEL) =
(double (*)(id, SEL))[self methodForSelector: sel];
v = (*imp)(self, sel);
}
val = [NSNumber numberWithDouble: v];
}
break;
default:
[NSException raise: NSInvalidArgumentException
format: @"key-value set method has unsupported type"];
}
return val;
}
}
static void
GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
const char *type, unsigned size, unsigned off)
{
if (sel != 0)
{
NSMethodSignature *sig = [self methodSignatureForSelector: sel];
if ([sig numberOfArguments] != 3)
{
[NSException raise: NSInvalidArgumentException
format: @"key-value set method has wrong number of args"];
}
type = [sig getArgumentTypeAtIndex: 2];
}
if (type == 0)
{
[self handleTakeValue: val forUnboundKey: key];
}
else
{
switch (*type)
{
case _C_ID:
case _C_CLASS:
{
id v = val;
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, id) =
(void (*)(id, SEL, id))[self methodForSelector: sel];
(*imp)(self, sel, val);
}
}
break;
case _C_CHR:
{
char v = [val charValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, char) =
(void (*)(id, SEL, char))[self methodForSelector: sel];
(*imp)(self, sel, v);
}
}
break;
case _C_UCHR:
{
unsigned char v = [val unsignedCharValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, unsigned char) =
(void (*)(id, SEL, unsigned char))[self methodForSelector:
sel];
(*imp)(self, sel, v);
}
}
break;
case _C_SHT:
{
short v = [val shortValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, short) =
(void (*)(id, SEL, short))[self methodForSelector: sel];
(*imp)(self, sel, v);
}
}
break;
case _C_USHT:
{
unsigned short v = [val unsignedShortValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, unsigned short) =
(void (*)(id, SEL, unsigned short))[self methodForSelector:
sel];
(*imp)(self, sel, v);
}
}
break;
case _C_INT:
{
int v = [val intValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, int) =
(void (*)(id, SEL, int))[self methodForSelector: sel];
(*imp)(self, sel, v);
}
}
break;
case _C_UINT:
{
unsigned int v = [val unsignedIntValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, unsigned int) =
(void (*)(id, SEL, unsigned int))[self methodForSelector:
sel];
(*imp)(self, sel, v);
}
}
break;
case _C_LNG:
{
long v = [val longValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, long) =
(void (*)(id, SEL, long))[self methodForSelector: sel];
(*imp)(self, sel, v);
}
}
break;
case _C_ULNG:
{
unsigned long v = [val unsignedLongValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, unsigned long) =
(void (*)(id, SEL, unsigned long))[self methodForSelector:
sel];
(*imp)(self, sel, v);
}
}
break;
#ifdef _C_LNG_LNG
case _C_LNG_LNG:
{
long long v = [val longLongValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, long long) =
(void (*)(id, SEL, long long))[self methodForSelector: sel];
(*imp)(self, sel, v);
}
}
break;
#endif
#ifdef _C_ULNG_LNG
case _C_ULNG_LNG:
{
unsigned long long v = [val unsignedLongLongValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, unsigned long long) =
(void (*)(id, SEL, unsigned long long))[self
methodForSelector: sel];
(*imp)(self, sel, v);
}
}
break;
#endif
case _C_FLT:
{
float v = [val floatValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, float) =
(void (*)(id, SEL, float))[self methodForSelector: sel];
(*imp)(self, sel, v);
}
}
break;
case _C_DBL:
{
double v = [val doubleValue];
if (sel == 0)
{
memcpy(((void*)self) + off, (void*)&v, size);
}
else
{
void (*imp)(id, SEL, double) =
(void (*)(id, SEL, double))[self methodForSelector: sel];
(*imp)(self, sel, v);
}
}
break;
default:
[NSException raise: NSInvalidArgumentException
format: @"key-value set method has unsupported type"];
}
}
}
+ (BOOL) accessInstanceVariablesDirectly + (BOOL) accessInstanceVariablesDirectly
{ {
return YES; return YES;
@ -1308,6 +1874,8 @@ static BOOL deallocNotifications = NO;
{ {
SEL sel = 0; SEL sel = 0;
const char *type = 0; const char *type = 0;
unsigned size;
unsigned off;
NSString *name; NSString *name;
if ([[self class] useStoredAccessor] == NO) if ([[self class] useStoredAccessor] == NO)
@ -1331,11 +1899,10 @@ static BOOL deallocNotifications = NO;
if ([[self class] accessInstanceVariablesDirectly] == YES) if ([[self class] accessInstanceVariablesDirectly] == YES)
{ {
name = [NSString stringWithFormat: @"_%@", aKey]; name = [NSString stringWithFormat: @"_%@", aKey];
type = GSInstanceVariableType(self, name); if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
if (type == 0)
{ {
name = aKey; name = aKey;
type = GSInstanceVariableType(self, name); GSInstanceVariableInfo(self, name, &type, &size, &off);
} }
} }
if (type == 0) if (type == 0)
@ -1355,28 +1922,16 @@ static BOOL deallocNotifications = NO;
} }
} }
if (sel != 0) return GSGetValue(self, aKey, sel, type, size, off);
{
return [self performSelector: sel];
}
else if (type != 0)
{
id v;
GSGetInstanceVariable(self, name, (void*)&v);
return v;
}
else
{
[self handleTakeValue: nil forUnboundKey: aKey];
return nil;
}
} }
- (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey - (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey
{ {
SEL sel = 0; SEL sel;
const char *type = 0; const char *type;
unsigned size;
unsigned off;
NSString *cap;
NSString *name; NSString *name;
if ([[self class] useStoredAccessor] == NO) if ([[self class] useStoredAccessor] == NO)
@ -1385,7 +1940,9 @@ static BOOL deallocNotifications = NO;
return; return;
} }
name = [NSString stringWithFormat: @"_set%@:", [aKey capitalizedString]]; cap = [aKey capitalizedString];
name = [NSString stringWithFormat: @"_set%@:", cap];
type = 0;
sel = NSSelectorFromString(name); sel = NSSelectorFromString(name);
if ([self respondsToSelector: sel] == NO) if ([self respondsToSelector: sel] == NO)
{ {
@ -1393,17 +1950,15 @@ static BOOL deallocNotifications = NO;
if ([[self class] accessInstanceVariablesDirectly] == YES) if ([[self class] accessInstanceVariablesDirectly] == YES)
{ {
name = [NSString stringWithFormat: @"_%@", aKey]; name = [NSString stringWithFormat: @"_%@", aKey];
type = GSInstanceVariableType(self, name); if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
if (type == 0)
{ {
name = aKey; name = aKey;
type = GSInstanceVariableType(self, name); GSInstanceVariableInfo(self, name, &type, &size, &off);
} }
} }
if (type == 0) if (type == 0)
{ {
name = [NSString stringWithFormat: @"set%@:", name = [NSString stringWithFormat: @"set%@:", cap];
[aKey capitalizedString]];
sel = NSSelectorFromString(name); sel = NSSelectorFromString(name);
if ([self respondsToSelector: sel] == NO) if ([self respondsToSelector: sel] == NO)
{ {
@ -1412,31 +1967,25 @@ static BOOL deallocNotifications = NO;
} }
} }
if (sel != 0) GSSetValue(self, anObject, aKey, sel, type, size, off);
{
[self performSelector: sel withObject: anObject];
}
else if (type != 0)
{
GSSetInstanceVariable(self, name, (void*)&anObject);
}
else
{
[self handleTakeValue: anObject forUnboundKey: aKey];
}
} }
- (void) takeValue: (id)anObject forKey: (NSString*)aKey - (void) takeValue: (id)anObject forKey: (NSString*)aKey
{ {
SEL sel = 0; SEL sel;
const char *type = 0; const char *type;
NSString *name = nil; unsigned size;
unsigned off;
NSString *cap;
NSString *name;
name = [NSString stringWithFormat: @"set%@:", [aKey capitalizedString]]; cap = [aKey capitalizedString];
name = [NSString stringWithFormat: @"set%@:", cap];
type = 0;
sel = NSSelectorFromString(name); sel = NSSelectorFromString(name);
if ([self respondsToSelector: sel] == NO) if ([self respondsToSelector: sel] == NO)
{ {
name = [NSString stringWithFormat: @"_set%@:", [aKey capitalizedString]]; name = [NSString stringWithFormat: @"_set%@:", cap];
sel = NSSelectorFromString(name); sel = NSSelectorFromString(name);
if ([self respondsToSelector: sel] == NO) if ([self respondsToSelector: sel] == NO)
{ {
@ -1444,28 +1993,16 @@ static BOOL deallocNotifications = NO;
if ([[self class] accessInstanceVariablesDirectly] == YES) if ([[self class] accessInstanceVariablesDirectly] == YES)
{ {
name = [NSString stringWithFormat: @"_%@", aKey]; name = [NSString stringWithFormat: @"_%@", aKey];
type = GSInstanceVariableType(self, name); if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
if (type == 0)
{ {
name = aKey; name = aKey;
type = GSInstanceVariableType(self, name); GSInstanceVariableInfo(self, name, &type, &size, &off);
} }
} }
} }
} }
if (sel != 0) GSSetValue(self, anObject, aKey, sel, type, size, off);
{
[self performSelector: sel withObject: anObject];
}
else if (type != 0)
{
GSSetInstanceVariable(self, name, (void*)&anObject);
}
else
{
[self handleTakeValue: anObject forUnboundKey: aKey];
}
} }
- (void) takeValue: (id)anObject forKeyPath: (NSString*)aKey - (void) takeValue: (id)anObject forKeyPath: (NSString*)aKey
@ -1514,6 +2051,8 @@ static BOOL deallocNotifications = NO;
SEL sel = 0; SEL sel = 0;
NSString *name = nil; NSString *name = nil;
const char *type = 0; const char *type = 0;
unsigned size;
unsigned off;
name = [NSString stringWithFormat: @"get%@", [aKey capitalizedString]]; name = [NSString stringWithFormat: @"get%@", [aKey capitalizedString]];
sel = NSSelectorFromString(name); sel = NSSelectorFromString(name);
@ -1541,30 +2080,14 @@ static BOOL deallocNotifications = NO;
if (sel == 0 && [[self class] accessInstanceVariablesDirectly] == YES) if (sel == 0 && [[self class] accessInstanceVariablesDirectly] == YES)
{ {
name = [NSString stringWithFormat: @"_%@", aKey]; name = [NSString stringWithFormat: @"_%@", aKey];
type = GSInstanceVariableType(self, name); if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
if (type == 0)
{ {
name = aKey; name = aKey;
type = GSInstanceVariableType(self, name); GSInstanceVariableInfo(self, name, &type, &size, &off);
} }
} }
if (sel != 0) return GSGetValue(self, aKey, sel, type, size, off);
{
return [self performSelector: sel];
}
else if (type != 0)
{
id v;
GSGetInstanceVariable(self, name, (void*)&v);
return v;
}
else
{
[self handleTakeValue: nil forUnboundKey: aKey];
return nil;
}
} }
- (id) valueForKeyPath: (NSString*)aKey - (id) valueForKeyPath: (NSString*)aKey