mirror of
https://github.com/gnustep/libs-gsweb.git
synced 2025-02-21 19:00:54 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gsweb/trunk@5815 72102866-910b-0410-8b05-ffd578937521
799 lines
22 KiB
Objective-C
799 lines
22 KiB
Objective-C
/* NSObject+IVarAccess+PerformSel.m
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
Written by: Manuel Guesdon <mguesdon@sbuilders.com>
|
|
Date: Jan 1999
|
|
|
|
This file is part of the GNUstep Web Library.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
static char rcsId[] = "$Id$";
|
|
|
|
#include <gsweb/GSWeb.framework/GSWeb.h>
|
|
|
|
NSMutableDictionary* objectIVarAccessCache_Set=nil;
|
|
NSMutableDictionary* objectIVarAccessCache_Get=nil;
|
|
NSLock* objectClassLock=nil;
|
|
|
|
//===================================================================================
|
|
typedef enum
|
|
{
|
|
NSObjectIVarsAccessType_Error = -1,
|
|
NSObjectIVarsAccessType_None = 0,
|
|
NSObjectIVarsAccessType_PerformSelector,
|
|
NSObjectIVarsAccessType_Invocation,
|
|
|
|
NSObjectIVarsAccessType_Direct,
|
|
|
|
NSObjectIVarsAccessType_Dictionary,
|
|
NSObjectIVarsAccessType_DictionaryWithRemoveObject,
|
|
NSObjectIVarsAccessType_DictionaryWithoutRemoveObject
|
|
|
|
} NSObjectIVarsAccessType;
|
|
|
|
//====================================================================
|
|
@interface NSObjectIVarsAccess : NSObject
|
|
{
|
|
@public
|
|
NSObjectIVarsAccessType accessType;
|
|
union
|
|
{
|
|
SEL selector;
|
|
NSInvocation* invocation;
|
|
struct objc_ivar* ivar;
|
|
} infos;
|
|
};
|
|
|
|
+(id)ivarAccess;
|
|
@end
|
|
|
|
//====================================================================
|
|
@implementation NSObjectIVarsAccess
|
|
|
|
//--------------------------------------------------------------------
|
|
+(id)ivarAccess
|
|
{
|
|
return [[self new]autorelease];
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(void)dealloc
|
|
{
|
|
if (accessType==NSObjectIVarsAccessType_Invocation)
|
|
{
|
|
DESTROY(infos.invocation);
|
|
};
|
|
[super dealloc];
|
|
};
|
|
@end
|
|
|
|
//====================================================================
|
|
struct objc_ivar* GSGetInstanceVariableStruct(id obj,NSString *iVarName)
|
|
{
|
|
const char* name=NULL;
|
|
Class class;
|
|
struct objc_ivar_list *ivars=NULL;
|
|
struct objc_ivar *ivar=NULL;
|
|
name=[iVarName cString];
|
|
class=[obj class];
|
|
while (class && !ivar)
|
|
{
|
|
ivars = class->ivars;
|
|
class = class->super_class;
|
|
if (ivars)
|
|
{
|
|
int i;
|
|
for (i=0;!ivar && i<ivars->ivar_count;i++)
|
|
{
|
|
if (strcmp(ivars->ivar_list[i].ivar_name, name)==0)
|
|
ivar = &ivars->ivar_list[i];
|
|
};
|
|
};
|
|
};
|
|
return ivar;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
const char* GSGetInstanceVariableType(id obj, NSString *iVarName)
|
|
{
|
|
struct objc_ivar *ivar = GSGetInstanceVariableStruct(obj,iVarName);
|
|
if (ivar)
|
|
return ivar->ivar_type;
|
|
else
|
|
return NULL;
|
|
};
|
|
|
|
//====================================================================
|
|
@implementation NSObject (IVarsAccess)
|
|
|
|
//--------------------------------------------------------------------
|
|
+(BOOL)isIVarAccessCachingDisabled
|
|
{
|
|
return NO;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
+(NSString*)getFunctionNameWithTemplate:(NSString*)tpl
|
|
forVariable:(NSString*)varName
|
|
uppercaseFirstLetter:(BOOL)uppercaseFirstLetter
|
|
{
|
|
NSString* fn=nil;
|
|
if (tpl && [tpl length]>0)
|
|
{
|
|
NSString* fnMain=nil;
|
|
if (uppercaseFirstLetter)
|
|
{
|
|
NSString* first=[[varName substringToIndex:1] uppercaseString];
|
|
NSString* next=[varName substringFromIndex:1];
|
|
fnMain=[NSString stringWithFormat:@"%@%@",first,next];
|
|
}
|
|
else
|
|
fnMain=varName;
|
|
fn=[NSString stringWithFormat:tpl,fnMain];
|
|
}
|
|
else
|
|
fn=[NSString stringWithString:varName];
|
|
return fn;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(SEL)getSelectorWithFunctionTemplate:(NSString*)tpl
|
|
forVariable:(NSString*)varName
|
|
uppercaseFirstLetter:(BOOL)uppercaseFirstLetter
|
|
{
|
|
NSString* fnName=nil;
|
|
SEL selector=NULL;
|
|
fnName=[NSObject getFunctionNameWithTemplate:tpl
|
|
forVariable:varName
|
|
uppercaseFirstLetter:uppercaseFirstLetter];
|
|
selector=NSSelectorFromString(fnName);
|
|
if (selector && ![self respondsToSelector:selector])
|
|
selector=NULL;
|
|
return selector;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
id PDataToId(const char* retType,void* pdata)
|
|
{
|
|
id value=nil;
|
|
switch(*retType)
|
|
{
|
|
case _C_CLASS:
|
|
value=*((id*)pdata);
|
|
break;
|
|
case _C_ID:
|
|
value=*((id*)pdata);
|
|
break;
|
|
case _C_CHR:
|
|
value=[NSNumber numberWithChar:*((char*)pdata)];
|
|
break;
|
|
case _C_UCHR:
|
|
value=[NSNumber numberWithUnsignedChar:*((unsigned char*)pdata)];
|
|
break;
|
|
case _C_SHT:
|
|
value=[NSNumber numberWithShort:*((short*)pdata)];
|
|
break;
|
|
case _C_USHT:
|
|
value=[NSNumber numberWithUnsignedShort:*((unsigned short*)pdata)];
|
|
break;
|
|
case _C_INT:
|
|
value=[NSNumber numberWithInt:*((int*)pdata)];
|
|
break;
|
|
case _C_UINT:
|
|
value=[NSNumber numberWithUnsignedInt:*((unsigned int*)pdata)];
|
|
break;
|
|
case _C_LNG:
|
|
value=[NSNumber numberWithLong:*((long*)pdata)];
|
|
break;
|
|
case _C_ULNG:
|
|
value=[NSNumber numberWithUnsignedLong:*((unsigned long*)pdata)];
|
|
break;
|
|
case _C_FLT:
|
|
value=[NSNumber numberWithFloat:*((float*)pdata)];
|
|
break;
|
|
case _C_DBL:
|
|
value=[NSNumber numberWithFloat:*((double*)pdata)];
|
|
break;
|
|
case _C_CHARPTR:
|
|
value=[NSString stringWithCString:*((char**)pdata)];
|
|
break;
|
|
case _C_SEL:
|
|
case _C_VOID:
|
|
case _C_PTR:
|
|
case _C_STRUCT_B:
|
|
default:
|
|
//TODO
|
|
break;
|
|
};
|
|
return value;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
void IdToPData(const char* retType,id _value,void* pdata)
|
|
{
|
|
switch(*retType)
|
|
{
|
|
case _C_CLASS:
|
|
*((Class*)pdata)=_value;
|
|
break;
|
|
case _C_ID:
|
|
*((id*)pdata)=_value;
|
|
break;
|
|
case _C_CHR:
|
|
*((char*)pdata)=[_value charValue];
|
|
break;
|
|
case _C_UCHR:
|
|
*((unsigned char*)pdata)=[_value unsignedCharValue];
|
|
break;
|
|
case _C_SHT:
|
|
*((short*)pdata)=[_value shortValue];
|
|
break;
|
|
case _C_USHT:
|
|
*((unsigned short*)pdata)=[_value unsignedShortValue];
|
|
break;
|
|
case _C_INT:
|
|
*((int*)pdata)=[_value intValue];
|
|
break;
|
|
case _C_UINT:
|
|
*((unsigned int*)pdata)=[_value unsignedIntValue];
|
|
break;
|
|
case _C_LNG:
|
|
*((long*)pdata)=[_value longValue];
|
|
break;
|
|
case _C_ULNG:
|
|
*((unsigned long*)pdata)=[_value unsignedLongValue];
|
|
break;
|
|
case _C_FLT:
|
|
*((float*)pdata)=[_value floatValue];
|
|
break;
|
|
case _C_DBL:
|
|
*((double*)pdata)=[_value doubleValue];
|
|
break;
|
|
case _C_CHARPTR:
|
|
case _C_SEL:
|
|
case _C_VOID:
|
|
case _C_PTR:
|
|
case _C_STRUCT_B:
|
|
default:
|
|
//TODO
|
|
break;
|
|
};
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)getIVarNamed:(NSString*)name_
|
|
withCacheObject:(NSObjectIVarsAccess*)ivarAccess_
|
|
{
|
|
id _value=nil;
|
|
switch(ivarAccess_->accessType)
|
|
{
|
|
case NSObjectIVarsAccessType_Error:
|
|
break;
|
|
case NSObjectIVarsAccessType_None:
|
|
break;
|
|
case NSObjectIVarsAccessType_PerformSelector:
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %@ %p (superClass:%@)with performSelector",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
_value=[self performSelector:ivarAccess_->infos.selector];
|
|
break;
|
|
case NSObjectIVarsAccessType_Invocation:
|
|
{
|
|
const char* retType=[[ivarAccess_->infos.invocation methodSignature] methodReturnType];
|
|
NSAssert([ivarAccess_->infos.invocation selector],@"No Selector in Invocation");
|
|
[ivarAccess_->infos.invocation setTarget:self];
|
|
[ivarAccess_->infos.invocation invoke];
|
|
if (*retType!=_C_VOID)
|
|
{
|
|
void* pdata=objc_atomic_malloc(objc_sizeof_type(retType));
|
|
if (!pdata)
|
|
{
|
|
//TODO
|
|
}
|
|
else
|
|
{
|
|
NSDebugMLLog(@"low",
|
|
@"getIVarNamed %@ in %@ %p (superClass:%@) with invocation (retType=%s)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass],
|
|
retType);
|
|
[ivarAccess_->infos.invocation getReturnValue:pdata];
|
|
_value=PDataToId(retType,pdata);
|
|
objc_free(pdata);
|
|
};
|
|
};
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_Direct:
|
|
{
|
|
const char* IVarType=ivarAccess_->infos.ivar->ivar_type;
|
|
unsigned int size=objc_sizeof_type(IVarType);
|
|
void* pdata=objc_atomic_malloc(size);
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %@ %p (superClass:%@) by variable ",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
if (pdata)
|
|
{
|
|
int offset = ivarAccess_->infos.ivar->ivar_offset;
|
|
memcpy(pdata,((void*)self)+offset, size);
|
|
_value=PDataToId(IVarType,pdata);
|
|
objc_free(pdata);
|
|
}
|
|
else
|
|
{
|
|
//TODO
|
|
};
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_Dictionary:
|
|
_value=[self objectForKey:name_];
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
return _value;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)getIVarNamed:(NSString*)name_
|
|
{
|
|
id _value=nil;
|
|
NSException* _exception=nil;
|
|
BOOL _cachindEnabled=YES;
|
|
Class _class=Nil;
|
|
NSObjectIVarsAccess* _ivarAccess=nil;
|
|
NSMutableDictionary* _classCache=nil;
|
|
// LOGObjectFnStart();
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %p %@ (superClass:%@)",name_,self,[self class],[self superclass]);
|
|
_class=[self class];
|
|
_classCache=[objectIVarAccessCache_Get objectForKey:_class];
|
|
if (!_classCache)
|
|
{
|
|
_cachindEnabled=![_class isIVarAccessCachingDisabled];
|
|
if (_cachindEnabled)
|
|
{
|
|
if (!objectClassLock)
|
|
objectClassLock=[NSLock new];
|
|
TmpLockBeforeDate(objectClassLock,[NSDate dateWithTimeIntervalSinceNow:GSLOCK_DELAY_S]);
|
|
_classCache=[NSMutableDictionary dictionary];
|
|
if (!objectIVarAccessCache_Get)
|
|
objectIVarAccessCache_Get=[NSMutableDictionary new];
|
|
[objectIVarAccessCache_Get setObject:_classCache
|
|
forKey:_class];
|
|
TmpUnlock(objectClassLock);
|
|
};
|
|
};
|
|
if (_cachindEnabled)
|
|
_ivarAccess=[_classCache objectForKey:name_];
|
|
if (!_ivarAccess)
|
|
{
|
|
SEL sel=NULL;
|
|
_ivarAccess=[NSObjectIVarsAccess ivarAccess];
|
|
sel=[self getSelectorWithFunctionTemplate:@"get%@"
|
|
forVariable:name_
|
|
uppercaseFirstLetter:YES];
|
|
if (!sel)
|
|
sel=[self getSelectorWithFunctionTemplate:@"%@"
|
|
forVariable:name_
|
|
uppercaseFirstLetter:NO];
|
|
NSDebugMLLog(@"low",@"getIVarNamed %@ in %@ %p sel=%p ",name_,[self class],self,(void*)sel);
|
|
if (sel)
|
|
{
|
|
NSMethodSignature* _sig = [self methodSignatureForSelector:sel];
|
|
if ([_sig numberOfArguments]!=2)
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't get Variable named %@ in %@ %p (superClass:%@): fn args mismatch",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
}
|
|
else
|
|
{
|
|
const char* retType=[_sig methodReturnType];
|
|
if (!retType)
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't get Variable named %@ in %@ %p (superClass:%@): fn unknown type",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
}
|
|
else
|
|
{
|
|
if (*retType==_C_ID)
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_PerformSelector;
|
|
_ivarAccess->infos.selector=sel;
|
|
}
|
|
else
|
|
{
|
|
NSInvocation* _invocation = [NSInvocation invocationWithMethodSignature:_sig];
|
|
[_invocation setSelector:sel];
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Invocation;
|
|
_ivarAccess->infos.invocation=_invocation;
|
|
NSAssert([_ivarAccess->infos.invocation selector],@"No Selector in Invocation");
|
|
[_ivarAccess->infos.invocation retain];
|
|
};
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{
|
|
struct objc_ivar* ivar=GSGetInstanceVariableStruct(self,name_);
|
|
if (ivar)
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Direct;
|
|
_ivarAccess->infos.ivar=ivar;
|
|
}
|
|
else
|
|
{
|
|
NSDebugMLLog(@"low",
|
|
@"getIVarNamed %@ in %@ %p (superClass:%@) with objectForKey ",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
if ([self respondsToSelector:@selector(objectForKey:)])
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Dictionary;
|
|
}
|
|
else
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't get Variable named %@ in %@ %p (superClass:%@) with objectForKey",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
};
|
|
};
|
|
};
|
|
|
|
if (_exception)
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Error;
|
|
if (_cachindEnabled)
|
|
{
|
|
if (!objectClassLock)
|
|
objectClassLock=[NSLock new];
|
|
TmpLockBeforeDate(objectClassLock,[NSDate dateWithTimeIntervalSinceNow:GSLOCK_DELAY_S]);
|
|
[_classCache setObject:_ivarAccess
|
|
forKey:name_];
|
|
TmpUnlock(objectClassLock);
|
|
};
|
|
};
|
|
if (_exception)
|
|
[_exception raise];
|
|
else
|
|
_value=[self getIVarNamed:name_
|
|
withCacheObject:_ivarAccess];
|
|
// LOGObjectFnStop();
|
|
return _value;
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(void)setIVarNamed:(NSString*)name_
|
|
withValue:(id)value_
|
|
withCacheObject:(NSObjectIVarsAccess*)ivarAccess_
|
|
{
|
|
LOGObjectFnStart();
|
|
switch(ivarAccess_->accessType)
|
|
{
|
|
case NSObjectIVarsAccessType_Error:
|
|
break;
|
|
case NSObjectIVarsAccessType_None:
|
|
break;
|
|
case NSObjectIVarsAccessType_PerformSelector:
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with performSelector value:%@",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass],
|
|
value_);
|
|
[self performSelector:ivarAccess_->infos.selector
|
|
withObject:value_];
|
|
break;
|
|
case NSObjectIVarsAccessType_Invocation:
|
|
{
|
|
const char* type=[[ivarAccess_->infos.invocation methodSignature] getArgumentTypeAtIndex:2];
|
|
void* pdata=objc_atomic_malloc(objc_sizeof_type(type));
|
|
IdToPData(type,value_,pdata);
|
|
NSAssert([ivarAccess_->infos.invocation selector],@"No Selector in Invocation");
|
|
[ivarAccess_->infos.invocation setTarget:self];
|
|
[ivarAccess_->infos.invocation setArgument:pdata
|
|
atIndex:2];
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with invocation value:%@",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass],
|
|
value_);
|
|
[ivarAccess_->infos.invocation invoke];
|
|
objc_free(pdata);
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_Direct:
|
|
{
|
|
const char* IVarType=ivarAccess_->infos.ivar->ivar_type;
|
|
if (IVarType)
|
|
{
|
|
unsigned int size=objc_sizeof_type(IVarType);
|
|
void* pdata=objc_atomic_malloc(size);
|
|
int offset = ivarAccess_->infos.ivar->ivar_offset;
|
|
IdToPData(IVarType,value_,pdata);
|
|
memcpy(((void*)self)+offset,pdata, size);
|
|
objc_free(pdata);
|
|
}
|
|
else
|
|
{
|
|
ExceptionRaise(@"NSObject IVar",
|
|
@"Can't set Variable named %@ in %@ %p (superClass:%@)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
};
|
|
};
|
|
break;
|
|
case NSObjectIVarsAccessType_DictionaryWithRemoveObject:
|
|
case NSObjectIVarsAccessType_DictionaryWithoutRemoveObject:
|
|
if (value_ || ivarAccess_->accessType==NSObjectIVarsAccessType_DictionaryWithoutRemoveObject)
|
|
{
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with setObjectForKey:",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
// keyvalue coding
|
|
[self setObject:value_
|
|
forKey:name_];
|
|
}
|
|
else
|
|
{
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with removeObjectForKey:",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
// keyvalue coding
|
|
[self removeObjectForKey:name_];
|
|
};
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
LOGObjectFnStop();
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(void)setIVarNamed:(NSString*)name_
|
|
withValue:(id)value_
|
|
{
|
|
NSException* _exception=nil;
|
|
BOOL _cachindEnabled=YES;
|
|
Class _class=[self class];
|
|
NSObjectIVarsAccess* _ivarAccess=nil;
|
|
NSMutableDictionary* _classCache=[objectIVarAccessCache_Set objectForKey:_class];
|
|
// LOGObjectFnStart();
|
|
NSDebugMLLog(@"low",@"LOG setIVarNamed:%@ withValue:%@ in %p %@ (superClass:%@)",name_,value_,self,[self class],[self superclass]);
|
|
if (!_classCache)
|
|
{
|
|
_cachindEnabled=![_class isIVarAccessCachingDisabled];
|
|
if (_cachindEnabled)
|
|
{
|
|
if (!objectClassLock)
|
|
objectClassLock=[NSLock new];
|
|
TmpLockBeforeDate(objectClassLock,[NSDate dateWithTimeIntervalSinceNow:GSLOCK_DELAY_S]);
|
|
_classCache=[NSMutableDictionary dictionary];
|
|
if (!objectIVarAccessCache_Set)
|
|
objectIVarAccessCache_Set=[NSMutableDictionary new];
|
|
[objectIVarAccessCache_Set setObject:_classCache
|
|
forKey:_class];
|
|
TmpUnlock(objectClassLock);
|
|
};
|
|
};
|
|
if (_cachindEnabled)
|
|
_ivarAccess=[_classCache objectForKey:name_];
|
|
if (!_ivarAccess)
|
|
{
|
|
SEL sel=NULL;
|
|
NSDebugMLLog(@"low",@"Not ivarAccess for name:%@",name_);
|
|
_ivarAccess=[NSObjectIVarsAccess ivarAccess];
|
|
// NSDebugMLLog(@"low",@"LOG setIVarNamed:%@ withValue:%@ in %@",name_,value_,[self class]);
|
|
sel=[self getSelectorWithFunctionTemplate:@"set%@:"
|
|
forVariable:name_
|
|
uppercaseFirstLetter:YES];
|
|
NSDebugMLLog(@"low",
|
|
@"sel=%ld (for %@ in %@)",
|
|
sel,name_,[self class]);
|
|
if (sel)
|
|
{
|
|
NSMethodSignature* _sig = [self methodSignatureForSelector:sel];
|
|
if ([_sig numberOfArguments]!=3)
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't set Variable named %@ in %@ %p (superClass:%@) (fn Bad number of Arguments)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
}
|
|
else
|
|
{
|
|
const char* type=[_sig getArgumentTypeAtIndex:2];
|
|
if (!type)
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't set Variable named %@ in %@ %p (superClass:%@) (fn get argument type)",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]];
|
|
}
|
|
else
|
|
{
|
|
if (*type==_C_ID)
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_PerformSelector;
|
|
_ivarAccess->infos.selector=sel;
|
|
NSDebugMLLog(@"low",
|
|
@"perform selector (IVar named :%@)",
|
|
name_);
|
|
}
|
|
else
|
|
{
|
|
NSInvocation* _invocation = [NSInvocation invocationWithMethodSignature:_sig];
|
|
[_invocation setSelector:sel];
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Invocation;
|
|
_ivarAccess->infos.invocation=_invocation;
|
|
NSAssert([_ivarAccess->infos.invocation selector],@"No Selector in Invocation");
|
|
[_ivarAccess->infos.invocation retain];
|
|
NSDebugMLLog(@"low",
|
|
@"invocation (IVar named :%@)",
|
|
name_);
|
|
};
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{
|
|
struct objc_ivar* ivar=GSGetInstanceVariableStruct(self,name_);
|
|
if (ivar)
|
|
{
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Direct;
|
|
_ivarAccess->infos.ivar=ivar;
|
|
NSDebugMLLog(@"low",
|
|
@"direct (IVar named :%@)",
|
|
name_);
|
|
}
|
|
else
|
|
{
|
|
BOOL _respondsToSetObject=NO;
|
|
BOOL _respondsToRemoveObject=NO;
|
|
NSDebugMLLog(@"low",
|
|
@"setIVarNamed %@ in %@ %p (superClass:%@) with dictionary ",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass]);
|
|
_respondsToSetObject=[self respondsToSelector:@selector(setObject:forKey:)];
|
|
_respondsToRemoveObject=[self respondsToSelector:@selector(removeObjectForKey:)];
|
|
if (_respondsToSetObject)
|
|
{
|
|
if (_respondsToRemoveObject)
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_DictionaryWithRemoveObject;
|
|
else
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_DictionaryWithoutRemoveObject;
|
|
}
|
|
else
|
|
{
|
|
_exception=[NSException exceptionWithName:@"NSObject IVar"
|
|
format:@"Can't set Variable named %@ in %@ %p (superClass:%@) value=%@",
|
|
name_,
|
|
[self class],
|
|
self,
|
|
[self superclass],
|
|
value_];
|
|
};
|
|
};
|
|
};
|
|
|
|
if (_exception)
|
|
_ivarAccess->accessType=NSObjectIVarsAccessType_Error;
|
|
if (_cachindEnabled)
|
|
{
|
|
if (!objectClassLock)
|
|
objectClassLock=[NSLock new];
|
|
TmpLockBeforeDate(objectClassLock,[NSDate dateWithTimeIntervalSinceNow:GSLOCK_DELAY_S]);
|
|
[_classCache setObject:_ivarAccess
|
|
forKey:name_];
|
|
TmpUnlock(objectClassLock);
|
|
};
|
|
};
|
|
if (_exception)
|
|
[_exception raise];
|
|
else
|
|
[self setIVarNamed:name_
|
|
withValue:value_
|
|
withCacheObject:_ivarAccess];
|
|
// LOGObjectFnStop();
|
|
};
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
#define PERFORM_SELECTOR_WITH_XX_VALUE \
|
|
id retValue=nil; \
|
|
NSMethodSignature* methodSignature=[NSObject methodSignatureForSelector:_selector]; \
|
|
const char* retType=[methodSignature methodReturnType]; \
|
|
NSInvocation* invocation= [NSInvocation invocationWithMethodSignature:methodSignature]; \
|
|
[invocation setTarget:self]; \
|
|
[invocation setSelector:_selector]; \
|
|
[invocation setArgument:&_value atIndex:2]; \
|
|
[invocation invoke]; \
|
|
if (retType && *retType==_C_ID) \
|
|
[invocation getReturnValue:&retValue]; \
|
|
return retValue;
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withIntValue:(int)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withFloatValue:(float)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withDoubleValue:(double)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withShortValue:(short)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
//--------------------------------------------------------------------
|
|
-(id)performSelector:(SEL)_selector
|
|
withUShortValue:(ushort)_value
|
|
{
|
|
PERFORM_SELECTOR_WITH_XX_VALUE
|
|
};
|
|
|
|
@end
|
|
|