libs-base/Source/NSObject.m
mccallum 3cdb041057 Some minor formatting changes.
([NSObject -classForArchiver]): Method removed; it's in NSArchiver.m.
([NSObject -replacementObjectForArchiver:]): Likewise.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@844 72102866-910b-0410-8b05-ffd578937521
1996-01-26 19:18:08 +00:00

672 lines
14 KiB
Objective-C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* Implementation of NSObject for GNUStep
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: August 1994
This file is part of the GNU Objective C Class 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.
*/
#include <objects/stdobjects.h>
#include <stdarg.h>
#include <Foundation/NSObject.h>
#include <objc/Protocol.h>
#include <objc/objc-api.h>
#include <Foundation/NSMethodSignature.h>
// #include <Foundation/NSArchiver.h>
// #include <Foundation/NSCoder.h>
#include <Foundation/NSInvocation.h>
#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSString.h>
#include <objects/collhash.h>
#include <objects/eltfuncs.h>
#include <limits.h>
extern void (*_objc_error)(id object, const char *format, va_list);
extern int errno;
/* Reference count management */
/* Doesn't handle multi-threaded stuff.
Doesn't handle exceptions. */
/* The hashtable of retain counts on objects */
static coll_cache_ptr retain_counts = NULL;
/* The Class responsible for handling autorelease's */
static id autorelease_class = nil;
/* When this is `YES', every call to release/autorelease, checks to make sure
isn't being set up to release itself too many times. */
static BOOL double_release_check_enabled = NO;
BOOL NSShouldRetainWithZone(NSObject *anObject, NSZone *requestedZone)
{
if (!requestedZone || [anObject zone] == requestedZone)
return YES;
else
return NO;
}
void NSIncrementExtraRefCount(id anObject)
{
coll_node_ptr n;
n = coll_hash_node_for_key(retain_counts, anObject);
if (n)
(n->value.unsigned_int_u)++;
else
coll_hash_add(&retain_counts, anObject, (unsigned)1);
}
BOOL NSDecrementExtraRefCountWasZero(id anObject)
{
BOOL wasZero = YES;
coll_node_ptr n;
n = coll_hash_node_for_key(retain_counts, anObject);
if (!n) return wasZero;
if (n->value.unsigned_int_u) wasZero = NO;
if (!--n->value.unsigned_int_u)
coll_hash_remove(retain_counts, anObject);
return wasZero;
}
@implementation NSObject
+ (void) initialize
{
if (self == [NSObject class])
{
retain_counts = coll_hash_new(64,
(coll_hash_func_type)
elt_hash_void_ptr,
(coll_compare_func_type)
elt_compare_void_ptrs);
autorelease_class = [NSAutoreleasePool class];
}
return;
}
+ (id) alloc
{
return [self allocWithZone:NS_NOZONE];
}
+ (id) allocWithZone: (NSZone*)z
{
return NSAllocateObject (self, 0, z);
}
+ (id) new
{
return [[self alloc] init];
}
- copyWithZone:(NSZone *)zone;
{
return NSCopyObject (self, 0, zone);
}
- (id) copy
{
return [self copyWithZone: NS_NOZONE];
}
- (void) dealloc
{
NSDeallocateObject (self);
}
- free
{
[self error:"Use `dealloc' instead of `free'."];
return nil;
}
- (id) init
{
return self;
}
- mutableCopyWithZone:(NSZone *)zone
{
return [self copyWithZone:zone];
}
- (id) mutableCopy
{
return [self mutableCopyWithZone: NS_NOZONE];
}
+ (Class) superclass
{
return class_get_super_class (self);
}
- (Class) superclass
{
return object_get_super_class (self);
}
+ (BOOL) instancesRespondToSelector: (SEL)aSelector
{
return (class_get_instance_method(self, aSelector) != METHOD_NULL);
}
+ (BOOL) conformsToProtocol: (Protocol*)aProtocol
{
int i;
struct objc_protocol_list* proto_list;
for (proto_list = ((struct objc_class*)self)->class_pointer->protocols;
proto_list; proto_list = proto_list->next)
{
for (i=0; i < proto_list->count; i++)
{
/* xxx We should add conformsToProtocol to Protocol class. */
if ([proto_list->list[i] conformsTo: aProtocol])
return YES;
}
}
if ([self superclass])
return [[self superclass] conformsToProtocol: aProtocol];
else
return NO;
}
- (BOOL) conformsToProtocol: (Protocol*)aProtocol
{
return [[self class] conformsToProtocol:aProtocol];
}
+ (IMP) instanceMethodForSelector: (SEL)aSelector
{
return method_get_imp(class_get_instance_method(self, aSelector));
}
- (IMP) methodForSelector: (SEL)aSelector
{
return (method_get_imp(object_is_instance(self)
?class_get_instance_method(self->isa, aSelector)
:class_get_class_method(self->isa, aSelector)));
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
{
[self notImplemented:_cmd];
return nil;
}
- (NSString*) description
{
return [NSString stringWithCString: object_get_class_name(self)];
}
+ (NSString*) description
{
return [NSString stringWithCString: class_get_class_name(self)];
}
+ (void) poseAsClass: (Class)aClassObject
{
class_pose_as(self, aClassObject);
}
- (void) doesNotRecognizeSelector: (SEL)aSelector
{
[self error:"%s does not recognize %s",
object_get_class_name(self), sel_get_name(aSelector)];
}
- (retval_t) forward:(SEL)aSel :(arglist_t)argFrame
{
#if 1
[self doesNotRecognizeSelector:aSel];
return NULL;
#else
void *retFrame;
NSMethodSignature *ms = [self methodSignatureForSelector:aSel];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature:ms
frame:argFrame];
/* is this right? */
retFrame = (void*) alloca([ms methodReturnLength]);
[self forwardInvocation:inv];
[inv getReturnValue:retFrame];
/* where do ms and inv get free'd? */
return retFrame;
#endif
}
- (void) forwardInvocation: (NSInvocation*)anInvocation
{
[self doesNotRecognizeSelector:[anInvocation selector]];
return;
}
- (id) awakeAfterUsingCoder: (NSCoder*)aDecoder
{
return self;
}
- (Class) classForCoder
{
return [self class];
}
- (id) replacementObjectForCoder: (NSCoder*)anEncoder
{
return self;
}
/* NSObject protocol */
- autorelease
{
if (double_release_check_enabled)
{
unsigned release_count;
unsigned retain_count = [self retainCount];
release_count = [autorelease_class autoreleaseCountForObject:self];
if (release_count > retain_count)
[self error:"Autorelease would release object too many times."];
}
[autorelease_class addObject:self];
return self;
}
+ autorelease
{
return self;
}
- (Class) class
{
return object_get_class(self);
}
- (unsigned) hash
{
return (unsigned)self;
}
- (BOOL) isEqual: anObject
{
return (self == anObject);
}
- (BOOL) isKindOfClass: (Class)aClass
{
Class class;
for (class = self->isa; class!=Nil; class = class_get_super_class(class))
if (class==aClass)
return YES;
return NO;
}
- (BOOL) isMemberOfClass: (Class)aClass
{
return self->isa==aClass;
}
- (BOOL) isProxy
{
return NO;
}
- perform: (SEL)aSelector
{
IMP msg = objc_msg_lookup(self, aSelector);
if (!msg)
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
return (*msg)(self, aSelector);
}
- perform: (SEL)aSelector withObject: anObject
{
IMP msg = objc_msg_lookup(self, aSelector);
if (!msg)
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
return (*msg)(self, aSelector, anObject);
}
- perform: (SEL)aSelector withObject: object1 withObject: object2
{
IMP msg = objc_msg_lookup(self, aSelector);
if (!msg)
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
return (*msg)(self, aSelector, object1, object2);
}
- (oneway void) release
{
if (double_release_check_enabled)
{
unsigned release_count;
unsigned retain_count = [self retainCount];
release_count = [autorelease_class autoreleaseCountForObject:self];
if (release_count > retain_count)
[self error:"Release would release object too many times."];
}
if (NSDecrementExtraRefCountWasZero(self))
[self dealloc];
return;
}
+ (oneway void) release
{
return;
}
- (BOOL) respondsToSelector: (SEL)aSelector
{
return ((object_is_instance(self)
?class_get_instance_method(self->isa, aSelector)
:class_get_class_method(self->isa, aSelector))!=METHOD_NULL);
}
- retain
{
NSIncrementExtraRefCount(self);
return self;
}
+ retain
{
return self;
}
- (unsigned) retainCount
{
coll_node_ptr n;
n = coll_hash_node_for_key(retain_counts, self);
if (n)
return n->value.unsigned_int_u;
else
return 0;
}
+ (unsigned) retainCount
{
return UINT_MAX;
}
- self
{
return self;
}
- (NSZone *)zone
{
return NSZoneFromPtr(self);
}
#if 1 /* waiting until I resolve type conflict with GNU Coding method */
- (void) encodeWithCoder: (NSCoder*)aCoder
{
return;
}
#endif
- initWithCoder: (NSCoder*)aDecoder
{
return self;
}
@end
@implementation NSObject (NEXTSTEP)
/* NEXTSTEP Object class compatibility */
- error:(const char *)aString, ...
{
#define FMT "error: %s (%s)\n%s\n"
char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self))
+((aString!=NULL)?strlen((char*)aString):0)+8)];
va_list ap;
sprintf(fmt, FMT, object_get_class_name(self),
object_is_instance(self)?"instance":"class",
(aString!=NULL)?aString:"");
va_start(ap, aString);
(*_objc_error)(self, fmt, ap);
va_end(ap);
return nil;
#undef FMT
}
- (const char *)name
{
return object_get_class_name(self);
}
- (BOOL)isKindOf:(Class)aClassObject
{
return [self isKindOfClass:aClassObject];
}
- (BOOL)isMemberOf:(Class)aClassObject
{
return [self isMemberOfClass:aClassObject];
}
+ (BOOL)instancesRespondTo:(SEL)aSel
{
return [self instancesRespondToSelector:aSel];
}
- (BOOL)respondsTo:(SEL)aSel
{
return [self respondsToSelector:aSel];
}
+ (BOOL) conformsTo: (Protocol*)aProtocol
{
return [self conformsToProtocol:aProtocol];
}
- (BOOL) conformsTo: (Protocol*)aProtocol
{
return [self conformsToProtocol:aProtocol];
}
- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame
{
return objc_msg_sendv(self, aSel, argFrame);
}
+ (IMP)instanceMethodFor:(SEL)aSel
{
return [self instanceMethodForSelector:aSel];
}
- (IMP)methodFor:(SEL)aSel
{
return [self methodForSelector:aSel];
}
+ poseAs:(Class)aClassObject
{
[self poseAsClass:aClassObject];
return self;
}
+ (int)version
{
return class_get_version(self);
}
+ setVersion:(int)aVersion
{
class_set_version(self, aVersion);
return self;
}
- notImplemented:(SEL)aSel
{
return [self error:"method %s not implemented", sel_get_name(aSel)];
}
- doesNotRecognize:(SEL)aSel
{
return [self error:"%s does not recognize %s",
object_get_class_name(self), sel_get_name(aSel)];
}
- perform: (SEL)sel with: anObject
{
return [self perform:sel withObject:anObject];
}
- perform: (SEL)sel with: anObject with: anotherObject
{
return [self perform:sel withObject:anObject withObject:anotherObject];
}
@end
@implementation NSObject (GNU)
/* GNU Object class compatibility */
+ (void) setAutoreleaseClass: (Class)aClass
{
autorelease_class = aClass;
}
+ (Class) autoreleaseClass
{
return autorelease_class;
}
+ (void) enableDoubleReleaseCheck: (BOOL)enable
{
double_release_check_enabled = enable;
}
- (int)compare:anotherObject;
{
if ([self isEqual:anotherObject])
return 0;
// Ordering objects by their address is pretty useless,
// so subclasses should override this is some useful way.
else if (self > anotherObject)
return 1;
else
return -1;
}
- (BOOL)isMetaClass
{
return NO;
}
- (BOOL)isClass
{
return object_is_class(self);
}
- (BOOL)isInstance
{
return object_is_instance(self);
}
- (BOOL)isMemberOfClassNamed:(const char *)aClassName
{
return ((aClassName!=NULL)
&&!strcmp(class_get_class_name(self->isa), aClassName));
}
+ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel
{
return ((struct objc_method_description *)
class_get_instance_method(self, aSel));
}
- (struct objc_method_description *)descriptionForMethod:(SEL)aSel
{
return ((struct objc_method_description *)
(object_is_instance(self)
?class_get_instance_method(self->isa, aSel)
:class_get_class_method(self->isa, aSel)));
}
- (Class)transmuteClassTo:(Class)aClassObject
{
if (object_is_instance(self))
if (class_is_class(aClassObject))
if (class_get_instance_size(aClassObject)==class_get_instance_size(isa))
if ([self isKindOfClass:aClassObject])
{
Class old_isa = isa;
isa = aClassObject;
return old_isa;
}
return nil;
}
- subclassResponsibility:(SEL)aSel
{
return [self error:"subclass should override %s", sel_get_name(aSel)];
}
- shouldNotImplement:(SEL)aSel
{
return [self error:"%s should not implement %s",
object_get_class_name(self), sel_get_name(aSel)];
}
+ (int)streamVersion: (TypedStream*)aStream
{
if (aStream->mode == OBJC_READONLY)
return objc_get_stream_class_version (aStream, self);
else
return class_get_version (self);
}
// These are used to write or read the instance variables
// declared in this particular part of the object. Subclasses
// should extend these, by calling [super read/write: aStream]
// before doing their own archiving. These methods are private, in
// the sense that they should only be called from subclasses.
- read: (TypedStream*)aStream
{
// [super read: aStream];
return self;
}
- write: (TypedStream*)aStream
{
// [super write: aStream];
return self;
}
- awake
{
// [super awake];
return self;
}
@end