From ae574b39a50b9123bdf17350f05ef0bdf848f9ad Mon Sep 17 00:00:00 2001 From: richard Date: Sat, 2 Dec 2000 21:36:56 +0000 Subject: [PATCH] key-value coding fixes git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@8246 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 4 +- Headers/gnustep/base/NSObjCRuntime.h | 3 +- Source/NSObjCRuntime.m | 84 +--- Source/NSObject.m | 679 ++++++++++++++++++++++++--- 4 files changed, 624 insertions(+), 146 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1c0b64177..53c570c64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,8 +3,8 @@ * Source/NSDate.m: GSTime() added millisecond info. * Source/NSCalendarDate.m: GSTime() added millisecond info. * Headers/Foundation/NSDate.h: GSTime() added millisecond info. - * Source/NSObject.m: key-value-coding restructured to simplify - future implementation for non-object values. + * Source/NSObject.m: key-value-coding restructured and + implemented for non-object values. 2000-11-30 Richard Frith-Macdonald diff --git a/Headers/gnustep/base/NSObjCRuntime.h b/Headers/gnustep/base/NSObjCRuntime.h index 88655f00a..07eb92150 100644 --- a/Headers/gnustep/base/NSObjCRuntime.h +++ b/Headers/gnustep/base/NSObjCRuntime.h @@ -77,8 +77,9 @@ GS_EXPORT void NSLogv (NSString* format, va_list args); * Get the type encoding for a named 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 const char *GSInstanceVariableType(id obj, NSString *name); GS_EXPORT BOOL GSSetInstanceVariable(id obj, NSString *name, const void* data); /* diff --git a/Source/NSObjCRuntime.m b/Source/NSObjCRuntime.m index 477a2381c..efc016cd3 100644 --- a/Source/NSObjCRuntime.m +++ b/Source/NSObjCRuntime.m @@ -70,17 +70,15 @@ NSGetSizeAndAlignment(const char *typePtr, unsigned *sizep, unsigned *alignp) *alignp = info.align; return typePtr; } - + 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]; Class class; struct objc_ivar_list *ivars; struct objc_ivar *ivar = 0; - int offset; - const char *type; - unsigned int size; class = [obj class]; while (class != nil && ivar == 0) @@ -106,86 +104,42 @@ GSGetInstanceVariable(id obj, NSString *iVarName, void *data) return NO; } - offset = ivar->ivar_offset; - type = ivar->ivar_type; - size = objc_sizeof_type(type); - memcpy(data, ((void*)obj) + offset, size); + if (*type) + *type = ivar->ivar_type; + if (*size) + *size = objc_sizeof_type(ivar->ivar_type); + if (*offset) + *offset = ivar->ivar_offset; return YES; } -const char* -GSInstanceVariableType(id obj, NSString *iVarName) +BOOL +GSGetInstanceVariable(id obj, NSString *iVarName, void *data) { - const char *name = [iVarName cString]; - Class class; - struct objc_ivar_list *ivars; - struct objc_ivar *ivar = 0; + int offset; + const char *type; + unsigned int size; - class = [obj class]; - while (class != nil && ivar == 0) + if (GSInstanceVariableInfo(obj, iVarName, &type, &size, &offset) == NO) { - 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 0; + return NO; } - return ivar->ivar_type; + memcpy(data, ((void*)obj) + offset, size); + return YES; } BOOL 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; const char *type; unsigned int size; - class = [obj class]; - 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) + if (GSInstanceVariableInfo(obj, iVarName, &type, &size, &offset) == NO) { return NO; } - - offset = ivar->ivar_offset; - type = ivar->ivar_type; - size = objc_sizeof_type(type); memcpy(((void*)obj) + offset, data, size); return YES; } diff --git a/Source/NSObject.m b/Source/NSObject.m index 648c70aa4..69d11446d 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -1277,12 +1277,578 @@ static BOOL deallocNotifications = NO; +#include #include #include @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 { return YES; @@ -1308,6 +1874,8 @@ static BOOL deallocNotifications = NO; { SEL sel = 0; const char *type = 0; + unsigned size; + unsigned off; NSString *name; if ([[self class] useStoredAccessor] == NO) @@ -1331,11 +1899,10 @@ static BOOL deallocNotifications = NO; if ([[self class] accessInstanceVariablesDirectly] == YES) { name = [NSString stringWithFormat: @"_%@", aKey]; - type = GSInstanceVariableType(self, name); - if (type == 0) + if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO) { name = aKey; - type = GSInstanceVariableType(self, name); + GSInstanceVariableInfo(self, name, &type, &size, &off); } } if (type == 0) @@ -1355,28 +1922,16 @@ static BOOL deallocNotifications = NO; } } - if (sel != 0) - { - 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; - } + return GSGetValue(self, aKey, sel, type, size, off); } - (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey { - SEL sel = 0; - const char *type = 0; + SEL sel; + const char *type; + unsigned size; + unsigned off; + NSString *cap; NSString *name; if ([[self class] useStoredAccessor] == NO) @@ -1385,7 +1940,9 @@ static BOOL deallocNotifications = NO; return; } - name = [NSString stringWithFormat: @"_set%@:", [aKey capitalizedString]]; + cap = [aKey capitalizedString]; + name = [NSString stringWithFormat: @"_set%@:", cap]; + type = 0; sel = NSSelectorFromString(name); if ([self respondsToSelector: sel] == NO) { @@ -1393,17 +1950,15 @@ static BOOL deallocNotifications = NO; if ([[self class] accessInstanceVariablesDirectly] == YES) { name = [NSString stringWithFormat: @"_%@", aKey]; - type = GSInstanceVariableType(self, name); - if (type == 0) + if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO) { name = aKey; - type = GSInstanceVariableType(self, name); + GSInstanceVariableInfo(self, name, &type, &size, &off); } } if (type == 0) { - name = [NSString stringWithFormat: @"set%@:", - [aKey capitalizedString]]; + name = [NSString stringWithFormat: @"set%@:", cap]; sel = NSSelectorFromString(name); if ([self respondsToSelector: sel] == NO) { @@ -1412,31 +1967,25 @@ static BOOL deallocNotifications = NO; } } - if (sel != 0) - { - [self performSelector: sel withObject: anObject]; - } - else if (type != 0) - { - GSSetInstanceVariable(self, name, (void*)&anObject); - } - else - { - [self handleTakeValue: anObject forUnboundKey: aKey]; - } + GSSetValue(self, anObject, aKey, sel, type, size, off); } - (void) takeValue: (id)anObject forKey: (NSString*)aKey { - SEL sel = 0; - const char *type = 0; - NSString *name = nil; + SEL sel; + const char *type; + 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); if ([self respondsToSelector: sel] == NO) { - name = [NSString stringWithFormat: @"_set%@:", [aKey capitalizedString]]; + name = [NSString stringWithFormat: @"_set%@:", cap]; sel = NSSelectorFromString(name); if ([self respondsToSelector: sel] == NO) { @@ -1444,28 +1993,16 @@ static BOOL deallocNotifications = NO; if ([[self class] accessInstanceVariablesDirectly] == YES) { name = [NSString stringWithFormat: @"_%@", aKey]; - type = GSInstanceVariableType(self, name); - if (type == 0) + if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO) { name = aKey; - type = GSInstanceVariableType(self, name); + GSInstanceVariableInfo(self, name, &type, &size, &off); } } } } - if (sel != 0) - { - [self performSelector: sel withObject: anObject]; - } - else if (type != 0) - { - GSSetInstanceVariable(self, name, (void*)&anObject); - } - else - { - [self handleTakeValue: anObject forUnboundKey: aKey]; - } + GSSetValue(self, anObject, aKey, sel, type, size, off); } - (void) takeValue: (id)anObject forKeyPath: (NSString*)aKey @@ -1514,6 +2051,8 @@ static BOOL deallocNotifications = NO; SEL sel = 0; NSString *name = nil; const char *type = 0; + unsigned size; + unsigned off; name = [NSString stringWithFormat: @"get%@", [aKey capitalizedString]]; sel = NSSelectorFromString(name); @@ -1541,30 +2080,14 @@ static BOOL deallocNotifications = NO; if (sel == 0 && [[self class] accessInstanceVariablesDirectly] == YES) { name = [NSString stringWithFormat: @"_%@", aKey]; - type = GSInstanceVariableType(self, name); - if (type == 0) + if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO) { name = aKey; - type = GSInstanceVariableType(self, name); + GSInstanceVariableInfo(self, name, &type, &size, &off); } } - if (sel != 0) - { - 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; - } + return GSGetValue(self, aKey, sel, type, size, off); } - (id) valueForKeyPath: (NSString*)aKey