2001-12-16 13:36:06 +00:00
|
|
|
|
/** Implementation of NSObject for GNUStep
|
1996-01-26 19:18:08 +00:00
|
|
|
|
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
1995-01-26 17:55:52 +00:00
|
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1995-01-26 17:55:52 +00:00
|
|
|
|
Date: August 1994
|
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1995-01-26 17:55:52 +00:00
|
|
|
|
|
|
|
|
|
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
|
1999-09-09 02:56:20 +00:00
|
|
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSObject class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
1995-01-26 17:55:52 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
|
#include <config.h>
|
1998-12-20 21:27:47 +00:00
|
|
|
|
#include <base/preface.h>
|
1995-03-12 15:40:22 +00:00
|
|
|
|
#include <stdarg.h>
|
1995-04-17 21:13:20 +00:00
|
|
|
|
#include <Foundation/NSObject.h>
|
1995-03-23 03:31:30 +00:00
|
|
|
|
#include <objc/Protocol.h>
|
1995-04-17 21:13:20 +00:00
|
|
|
|
#include <Foundation/NSMethodSignature.h>
|
|
|
|
|
#include <Foundation/NSInvocation.h>
|
|
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
1995-08-24 22:24:17 +00:00
|
|
|
|
#include <Foundation/NSString.h>
|
1998-12-18 17:05:44 +00:00
|
|
|
|
#include <Foundation/NSArray.h>
|
1996-03-26 20:59:42 +00:00
|
|
|
|
#include <Foundation/NSException.h>
|
1998-10-11 06:26:40 +00:00
|
|
|
|
#include <Foundation/NSPortCoder.h>
|
|
|
|
|
#include <Foundation/NSDistantObject.h>
|
1997-03-03 19:46:52 +00:00
|
|
|
|
#include <Foundation/NSZone.h>
|
1999-09-28 19:35:09 +00:00
|
|
|
|
#include <Foundation/NSDebug.h>
|
1999-12-13 12:14:01 +00:00
|
|
|
|
#include <Foundation/NSThread.h>
|
|
|
|
|
#include <Foundation/NSNotification.h>
|
2000-10-31 11:05:23 +00:00
|
|
|
|
#include <Foundation/NSObjCRuntime.h>
|
1995-04-05 01:54:16 +00:00
|
|
|
|
#include <limits.h>
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
2002-01-30 13:05:35 +00:00
|
|
|
|
|
|
|
|
|
|
2001-08-03 20:43:40 +00:00
|
|
|
|
#ifndef NeXT_RUNTIME
|
1999-06-24 19:30:29 +00:00
|
|
|
|
extern BOOL __objc_responds_to(id, SEL);
|
2001-08-03 20:43:40 +00:00
|
|
|
|
#endif
|
1999-06-24 19:30:29 +00:00
|
|
|
|
|
1998-11-12 10:58:17 +00:00
|
|
|
|
@class _FastMallocBuffer;
|
|
|
|
|
static Class fastMallocClass;
|
|
|
|
|
static unsigned fastMallocOffset;
|
|
|
|
|
|
2001-06-06 15:18:28 +00:00
|
|
|
|
static Class NSConstantStringClass;
|
2000-10-09 04:41:18 +00:00
|
|
|
|
|
1998-10-21 11:56:58 +00:00
|
|
|
|
@class NSDataMalloc;
|
|
|
|
|
@class NSMutableDataMalloc;
|
|
|
|
|
|
2002-01-06 11:26:49 +00:00
|
|
|
|
static BOOL deallocNotifications = NO;
|
|
|
|
|
|
1996-05-31 14:23:23 +00:00
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* Reference count and memory management
|
|
|
|
|
*
|
|
|
|
|
* If REFCNT_LOCAL is defined, reference counts for object are stored
|
|
|
|
|
* with the object, otherwise they are stored in a global map table
|
|
|
|
|
* that has to be protected by mutexes in a multithreraded environment.
|
|
|
|
|
* You therefore want REFCNT_LOCAL defined for best performance.
|
|
|
|
|
*
|
|
|
|
|
* If CACHE_ZONE is defined, the zone in which an object has been
|
|
|
|
|
* allocated is stored with the object - this makes lookup of the
|
|
|
|
|
* correct zone to free memory very fast.
|
|
|
|
|
*/
|
|
|
|
|
|
2002-02-02 07:10:51 +00:00
|
|
|
|
|
1999-12-13 12:14:01 +00:00
|
|
|
|
/*
|
|
|
|
|
* retain_counts_gate is needed when running multi-threaded for retain/release
|
|
|
|
|
* to work reliably.
|
|
|
|
|
*/
|
|
|
|
|
static objc_mutex_t retain_counts_gate = NULL;
|
|
|
|
|
|
2002-01-03 20:39:12 +00:00
|
|
|
|
#if GS_WITH_GC == 0 && !defined(NeXT_RUNTIME)
|
2002-02-02 07:10:51 +00:00
|
|
|
|
#define REFCNT_LOCAL 1
|
|
|
|
|
#define CACHE_ZONE 1
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif
|
1998-08-04 09:22:51 +00:00
|
|
|
|
|
2001-12-28 03:40:03 +00:00
|
|
|
|
#ifdef ALIGN
|
|
|
|
|
#undef ALIGN
|
|
|
|
|
#endif
|
|
|
|
|
#define ALIGN __alignof__(double)
|
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#if defined(REFCNT_LOCAL) || defined(CACHE_ZONE)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Define a structure to hold information that is held locally
|
|
|
|
|
* (before the start) in each object.
|
|
|
|
|
*/
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
|
|
|
|
typedef struct obj_layout_unpadded {
|
|
|
|
|
#if defined(REFCNT_LOCAL)
|
|
|
|
|
unsigned retained;
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(CACHE_ZONE)
|
|
|
|
|
NSZone *zone;
|
|
|
|
|
#endif
|
|
|
|
|
} unp;
|
1998-10-15 05:03:16 +00:00
|
|
|
|
#define UNP sizeof(unp)
|
1998-08-13 20:45:32 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now do the REAL version - using the other version to determine
|
|
|
|
|
* what padding (if any) is required to get the alignment of the
|
|
|
|
|
* structure correct.
|
|
|
|
|
*/
|
1999-02-02 00:08:58 +00:00
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
struct obj_layout {
|
|
|
|
|
#if defined(REFCNT_LOCAL)
|
|
|
|
|
unsigned retained;
|
|
|
|
|
#endif
|
|
|
|
|
#if defined(CACHE_ZONE)
|
|
|
|
|
NSZone *zone;
|
|
|
|
|
#endif
|
1998-10-15 05:03:16 +00:00
|
|
|
|
char padding[ALIGN - ((UNP % ALIGN) ? (UNP % ALIGN) : ALIGN)];
|
1998-08-04 09:22:51 +00:00
|
|
|
|
};
|
|
|
|
|
typedef struct obj_layout *obj;
|
|
|
|
|
|
|
|
|
|
#endif /* defined(REFCNT_LOCAL) || defined(CACHE_ZONE) */
|
|
|
|
|
|
|
|
|
|
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
|
1999-05-21 18:14:48 +00:00
|
|
|
|
unsigned
|
|
|
|
|
NSExtraRefCount(id anObject)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
1999-01-28 17:21:03 +00:00
|
|
|
|
void
|
|
|
|
|
NSIncrementExtraRefCount(id anObject)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
#define NSIncrementExtraRefCount(X)
|
|
|
|
|
BOOL
|
|
|
|
|
NSDecrementExtraRefCountWasZero(id anObject)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
#define NSDecrementExtraRefCountWasZero(X) NO
|
|
|
|
|
|
|
|
|
|
#else /* GS_WITH_GC */
|
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* Now do conditional compilation of reference count functions
|
|
|
|
|
* depending on whether we are using local or global counting.
|
|
|
|
|
*/
|
|
|
|
|
#if defined(REFCNT_LOCAL)
|
1999-12-10 00:59:40 +00:00
|
|
|
|
|
1999-05-21 18:14:48 +00:00
|
|
|
|
unsigned
|
|
|
|
|
NSExtraRefCount(id anObject)
|
|
|
|
|
{
|
|
|
|
|
return ((obj)anObject)[-1].retained;
|
|
|
|
|
}
|
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
void
|
|
|
|
|
NSIncrementExtraRefCount(id anObject)
|
|
|
|
|
{
|
1999-12-13 12:14:01 +00:00
|
|
|
|
if (retain_counts_gate != 0)
|
|
|
|
|
{
|
|
|
|
|
objc_mutex_lock(retain_counts_gate);
|
|
|
|
|
((obj)anObject)[-1].retained++;
|
|
|
|
|
objc_mutex_unlock (retain_counts_gate);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
((obj)anObject)[-1].retained++;
|
|
|
|
|
}
|
1998-08-04 09:22:51 +00:00
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
1999-12-13 12:14:01 +00:00
|
|
|
|
#define NSIncrementExtraRefCount(X) ({ \
|
|
|
|
|
if (retain_counts_gate != 0) \
|
|
|
|
|
{ \
|
|
|
|
|
objc_mutex_lock(retain_counts_gate); \
|
|
|
|
|
((obj)(X))[-1].retained++; \
|
|
|
|
|
objc_mutex_unlock(retain_counts_gate); \
|
|
|
|
|
} \
|
|
|
|
|
else \
|
|
|
|
|
{ \
|
|
|
|
|
((obj)X)[-1].retained++; \
|
|
|
|
|
} \
|
|
|
|
|
})
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
BOOL
|
|
|
|
|
NSDecrementExtraRefCountWasZero(id anObject)
|
|
|
|
|
{
|
1999-12-13 12:14:01 +00:00
|
|
|
|
if (retain_counts_gate != 0)
|
|
|
|
|
{
|
|
|
|
|
objc_mutex_lock(retain_counts_gate);
|
|
|
|
|
if (((obj)anObject)[-1].retained-- == 0)
|
1999-12-10 00:59:40 +00:00
|
|
|
|
{
|
1999-12-13 12:14:01 +00:00
|
|
|
|
objc_mutex_unlock(retain_counts_gate);
|
1999-12-10 00:59:40 +00:00
|
|
|
|
return YES;
|
1999-12-13 12:14:01 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
objc_mutex_unlock(retain_counts_gate);
|
1999-12-10 00:59:40 +00:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
1999-12-13 12:14:01 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (((obj)anObject)[-1].retained-- == 0)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-08-04 09:22:51 +00:00
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
1999-05-21 18:14:48 +00:00
|
|
|
|
#define NSExtraRefCount(X) (((obj)(X))[-1].retained)
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#else
|
1995-08-04 20:52:07 +00:00
|
|
|
|
|
2002-01-30 13:05:35 +00:00
|
|
|
|
#define GSI_MAP_EQUAL(M, X, Y) (X.obj == Y.obj)
|
2002-02-02 07:10:51 +00:00
|
|
|
|
#define GSI_MAP_HASH(M, X) (X.uint >> 2)
|
2002-01-30 13:05:35 +00:00
|
|
|
|
#define GSI_MAP_RETAIN_KEY(M, X)
|
|
|
|
|
#define GSI_MAP_RELEASE_KEY(M, X)
|
|
|
|
|
#define GSI_MAP_RETAIN_VAL(M, X)
|
|
|
|
|
#define GSI_MAP_RELEASE_VAL(M, X)
|
2002-02-02 07:10:51 +00:00
|
|
|
|
#define GSI_MAP_KTYPES GSUNION_OBJ|GSUNION_INT
|
2002-01-30 13:05:35 +00:00
|
|
|
|
#define GSI_MAP_VTYPES GSUNION_INT
|
2002-02-13 18:49:32 +00:00
|
|
|
|
#define GSI_MAP_NOCLEAN 1
|
2002-01-30 13:05:35 +00:00
|
|
|
|
|
|
|
|
|
#include <base/GSIMap.h>
|
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
/* The maptable of retain counts on objects */
|
2002-01-30 13:05:35 +00:00
|
|
|
|
static GSIMapTable_t retain_counts;
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
void
|
|
|
|
|
NSIncrementExtraRefCount (id anObject)
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2002-01-30 13:05:35 +00:00
|
|
|
|
GSIMapNode node;
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
1999-12-13 12:14:01 +00:00
|
|
|
|
if (retain_counts_gate != 0)
|
|
|
|
|
{
|
|
|
|
|
objc_mutex_lock(retain_counts_gate);
|
2002-01-30 13:05:35 +00:00
|
|
|
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
|
|
|
|
if (node != 0)
|
|
|
|
|
{
|
|
|
|
|
(node->value.uint)++;
|
|
|
|
|
}
|
1999-12-13 12:14:01 +00:00
|
|
|
|
else
|
2002-01-30 13:05:35 +00:00
|
|
|
|
{
|
2002-02-02 07:10:51 +00:00
|
|
|
|
GSIMapAddPair(&retain_counts, (GSIMapKey)anObject, (GSIMapVal)1);
|
2002-01-30 13:05:35 +00:00
|
|
|
|
}
|
1999-12-13 12:14:01 +00:00
|
|
|
|
objc_mutex_unlock(retain_counts_gate);
|
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
else
|
1999-12-13 12:14:01 +00:00
|
|
|
|
{
|
2002-01-30 13:05:35 +00:00
|
|
|
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
|
|
|
|
if (node != 0)
|
|
|
|
|
{
|
|
|
|
|
(node->value.uint)++;
|
|
|
|
|
}
|
1999-12-13 12:14:01 +00:00
|
|
|
|
else
|
2002-01-30 13:05:35 +00:00
|
|
|
|
{
|
2002-02-02 07:10:51 +00:00
|
|
|
|
GSIMapAddPair(&retain_counts, (GSIMapKey)anObject, (GSIMapVal)1);
|
2002-01-30 13:05:35 +00:00
|
|
|
|
}
|
1999-12-13 12:14:01 +00:00
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
BOOL
|
|
|
|
|
NSDecrementExtraRefCountWasZero (id anObject)
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2002-01-30 13:05:35 +00:00
|
|
|
|
GSIMapNode node;
|
1996-02-22 23:12:19 +00:00
|
|
|
|
|
1999-12-13 12:14:01 +00:00
|
|
|
|
if (retain_counts_gate != 0)
|
1996-07-15 18:41:44 +00:00
|
|
|
|
{
|
1999-12-13 12:14:01 +00:00
|
|
|
|
objc_mutex_lock(retain_counts_gate);
|
2002-01-30 13:05:35 +00:00
|
|
|
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
|
|
|
|
if (node == 0)
|
1999-12-13 12:14:01 +00:00
|
|
|
|
{
|
|
|
|
|
objc_mutex_unlock(retain_counts_gate);
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2002-01-30 13:05:35 +00:00
|
|
|
|
NSCAssert(node->value.uint > 0, NSInternalInconsistencyException);
|
|
|
|
|
if (--(node->value.uint) == 0)
|
1999-12-13 12:14:01 +00:00
|
|
|
|
{
|
2002-01-30 13:05:35 +00:00
|
|
|
|
GSIMapRemoveKey((GSIMapTable)&retain_counts, (GSIMapKey)anObject);
|
1999-12-13 12:14:01 +00:00
|
|
|
|
}
|
|
|
|
|
objc_mutex_unlock(retain_counts_gate);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2002-01-30 13:05:35 +00:00
|
|
|
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
|
|
|
|
if (node == 0)
|
1999-12-13 12:14:01 +00:00
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2002-01-30 13:05:35 +00:00
|
|
|
|
NSCAssert(node->value.uint > 0, NSInternalInconsistencyException);
|
|
|
|
|
if (--(node->value.uint) == 0)
|
1999-12-13 12:14:01 +00:00
|
|
|
|
{
|
2002-01-30 13:05:35 +00:00
|
|
|
|
GSIMapRemoveKey((GSIMapTable)&retain_counts, (GSIMapKey)anObject);
|
1999-12-13 12:14:01 +00:00
|
|
|
|
}
|
1996-07-15 18:41:44 +00:00
|
|
|
|
}
|
1996-02-22 23:12:19 +00:00
|
|
|
|
return NO;
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
1994-11-08 16:44:01 +00:00
|
|
|
|
|
1999-05-21 18:14:48 +00:00
|
|
|
|
unsigned
|
|
|
|
|
NSExtraRefCount (id anObject)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2002-01-30 13:05:35 +00:00
|
|
|
|
GSIMapNode node;
|
|
|
|
|
unsigned ret;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-12-13 12:14:01 +00:00
|
|
|
|
if (retain_counts_gate != 0)
|
|
|
|
|
{
|
|
|
|
|
objc_mutex_lock(retain_counts_gate);
|
2002-01-30 13:05:35 +00:00
|
|
|
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
|
|
|
|
if (node == 0)
|
1999-12-13 12:14:01 +00:00
|
|
|
|
{
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
2002-01-30 13:05:35 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = node->value.uint;
|
|
|
|
|
}
|
1999-12-13 12:14:01 +00:00
|
|
|
|
objc_mutex_unlock(retain_counts_gate);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2002-01-30 13:05:35 +00:00
|
|
|
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
|
|
|
|
if (node == 0)
|
1999-12-13 12:14:01 +00:00
|
|
|
|
{
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
2002-01-30 13:05:35 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret = node->value.uint;
|
|
|
|
|
}
|
1999-12-13 12:14:01 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return ret; /* ExtraRefCount + 1 */
|
|
|
|
|
}
|
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#endif /* defined(REFCNT_LOCAL) */
|
|
|
|
|
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif /* GS_WITH_GC */
|
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now do conditional compilation of memory allocation functions
|
|
|
|
|
* depending on what information (if any) we are storing before
|
|
|
|
|
* the start of each object.
|
|
|
|
|
*/
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
|
1999-09-29 14:13:52 +00:00
|
|
|
|
#include <gc.h>
|
|
|
|
|
#include <gc_typed.h>
|
|
|
|
|
|
1999-01-28 17:21:03 +00:00
|
|
|
|
inline NSZone *
|
2000-10-31 16:17:33 +00:00
|
|
|
|
GSObjCZone(NSObject *object)
|
1999-01-28 17:21:03 +00:00
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
GSFinalize(void* object, void* data)
|
|
|
|
|
{
|
|
|
|
|
[(id)object gcFinalize];
|
|
|
|
|
#ifndef NDEBUG
|
2001-04-19 16:10:23 +00:00
|
|
|
|
GSDebugAllocationRemove(((id)object)->class_pointer, (id)object);
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif
|
1999-09-28 10:25:42 +00:00
|
|
|
|
((id)object)->class_pointer = (void*)0xdeadface;
|
1999-01-28 17:21:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline NSObject *
|
1999-09-28 10:25:42 +00:00
|
|
|
|
NSAllocateObject(Class aClass, unsigned extraBytes, NSZone *zone)
|
1999-01-28 17:21:03 +00:00
|
|
|
|
{
|
1999-09-28 10:25:42 +00:00
|
|
|
|
id new = nil;
|
|
|
|
|
int size = aClass->instance_size + extraBytes;
|
|
|
|
|
|
1999-09-29 14:13:52 +00:00
|
|
|
|
NSCAssert((CLS_ISCLASS(aClass)), @"Bad class for new object");
|
|
|
|
|
if (zone == GSAtomicMallocZone())
|
|
|
|
|
{
|
|
|
|
|
new = NSZoneMalloc(zone, size);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-09-29 20:15:17 +00:00
|
|
|
|
GC_descr gc_type = (GC_descr)aClass->gc_object_type;
|
1999-09-29 14:13:52 +00:00
|
|
|
|
|
|
|
|
|
if (gc_type == 0)
|
|
|
|
|
{
|
|
|
|
|
new = NSZoneMalloc(zone, size);
|
2000-10-31 16:17:33 +00:00
|
|
|
|
NSLog(@"No garbage collection information for '%s'",
|
|
|
|
|
GSObjCName(aClass));
|
1999-09-29 14:13:52 +00:00
|
|
|
|
}
|
2000-07-04 10:17:03 +00:00
|
|
|
|
else if ([aClass requiresTypedMemory])
|
1999-09-29 14:13:52 +00:00
|
|
|
|
{
|
|
|
|
|
new = GC_CALLOC_EXPLICTLY_TYPED(1, size, gc_type);
|
|
|
|
|
}
|
2000-07-04 10:17:03 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
new = NSZoneMalloc(zone, size);
|
|
|
|
|
}
|
1999-09-29 14:13:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-01-28 17:21:03 +00:00
|
|
|
|
if (new != nil)
|
|
|
|
|
{
|
1999-09-28 10:25:42 +00:00
|
|
|
|
memset(new, 0, size);
|
1999-01-28 17:21:03 +00:00
|
|
|
|
new->class_pointer = aClass;
|
1999-09-28 10:25:42 +00:00
|
|
|
|
if (__objc_responds_to(new, @selector(gcFinalize)))
|
|
|
|
|
{
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#ifndef NDEBUG
|
1999-09-28 10:25:42 +00:00
|
|
|
|
/*
|
|
|
|
|
* We only do allocation counting for objects that can be
|
|
|
|
|
* finalised - for other objects we have no way of decrementing
|
|
|
|
|
* the count when the object is collected.
|
|
|
|
|
*/
|
2001-04-19 16:10:23 +00:00
|
|
|
|
GSDebugAllocationAdd(aClass, new);
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif
|
1999-09-28 10:25:42 +00:00
|
|
|
|
GC_REGISTER_FINALIZER (new, GSFinalize, NULL, NULL, NULL);
|
|
|
|
|
}
|
1999-01-28 17:21:03 +00:00
|
|
|
|
}
|
|
|
|
|
return new;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
NSDeallocateObject(NSObject *anObject)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else /* GS_WITH_GC */
|
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#if defined(REFCNT_LOCAL) || defined(CACHE_ZONE)
|
|
|
|
|
|
1998-10-15 05:03:16 +00:00
|
|
|
|
#if defined(CACHE_ZONE)
|
|
|
|
|
|
|
|
|
|
inline NSZone *
|
2000-10-31 16:17:33 +00:00
|
|
|
|
GSObjCZone(NSObject *object)
|
1998-10-15 05:03:16 +00:00
|
|
|
|
{
|
2001-06-06 15:18:28 +00:00
|
|
|
|
if (GSObjCClass(object) == NSConstantStringClass)
|
1999-01-28 17:21:03 +00:00
|
|
|
|
return NSDefaultMallocZone();
|
|
|
|
|
return ((obj)object)[-1].zone;
|
1998-10-15 05:03:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else /* defined(CACHE_ZONE) */
|
|
|
|
|
|
|
|
|
|
inline NSZone *
|
2000-10-31 16:17:33 +00:00
|
|
|
|
GSObjCZone(NSObject *object)
|
1998-10-15 05:03:16 +00:00
|
|
|
|
{
|
2001-06-06 15:18:28 +00:00
|
|
|
|
if (GSObjCClass(object) == NSConstantStringClass)
|
1999-01-28 17:21:03 +00:00
|
|
|
|
return NSDefaultMallocZone();
|
|
|
|
|
return NSZoneFromPointer(&((obj)object)[-1]);
|
1998-10-15 05:03:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* defined(CACHE_ZONE) */
|
|
|
|
|
|
1998-11-12 08:02:48 +00:00
|
|
|
|
inline NSObject *
|
|
|
|
|
NSAllocateObject (Class aClass, unsigned extraBytes, NSZone *zone)
|
1998-08-04 09:22:51 +00:00
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
|
#ifndef NDEBUG
|
2001-04-19 16:10:23 +00:00
|
|
|
|
extern void GSDebugAllocationAdd(Class c, id o);
|
1999-06-24 19:30:29 +00:00
|
|
|
|
#endif
|
1998-08-04 09:22:51 +00:00
|
|
|
|
id new = nil;
|
|
|
|
|
int size = aClass->instance_size + extraBytes + sizeof(struct obj_layout);
|
|
|
|
|
if (CLS_ISCLASS (aClass))
|
|
|
|
|
{
|
|
|
|
|
if (zone == 0)
|
|
|
|
|
zone = NSDefaultMallocZone();
|
|
|
|
|
new = NSZoneMalloc(zone, size);
|
|
|
|
|
}
|
|
|
|
|
if (new != nil)
|
|
|
|
|
{
|
|
|
|
|
memset (new, 0, size);
|
|
|
|
|
#if defined(CACHE_ZONE)
|
|
|
|
|
((obj)new)->zone = zone;
|
|
|
|
|
#endif
|
|
|
|
|
new = (id)&((obj)new)[1];
|
|
|
|
|
new->class_pointer = aClass;
|
|
|
|
|
#ifndef NDEBUG
|
2001-04-19 16:10:23 +00:00
|
|
|
|
GSDebugAllocationAdd(aClass, new);
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#endif
|
1998-10-15 05:03:16 +00:00
|
|
|
|
}
|
1998-08-04 09:22:51 +00:00
|
|
|
|
return new;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-12 08:02:48 +00:00
|
|
|
|
inline void
|
|
|
|
|
NSDeallocateObject(NSObject *anObject)
|
1998-08-04 09:22:51 +00:00
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
|
#ifndef NDEBUG
|
2001-04-19 16:10:23 +00:00
|
|
|
|
extern void GSDebugAllocationRemove(Class c, id o);
|
1999-06-24 19:30:29 +00:00
|
|
|
|
#endif
|
1998-08-04 09:22:51 +00:00
|
|
|
|
if ((anObject!=nil) && CLS_ISCLASS(((id)anObject)->class_pointer))
|
|
|
|
|
{
|
|
|
|
|
obj o = &((obj)anObject)[-1];
|
2000-10-31 16:17:33 +00:00
|
|
|
|
NSZone *z = GSObjCZone(anObject);
|
1998-08-04 09:22:51 +00:00
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2001-04-19 16:10:23 +00:00
|
|
|
|
GSDebugAllocationRemove(((id)anObject)->class_pointer, (id)anObject);
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#endif
|
|
|
|
|
((id)anObject)->class_pointer = (void*) 0xdeadface;
|
|
|
|
|
NSZoneFree(z, o);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
1998-10-15 05:03:16 +00:00
|
|
|
|
inline NSZone *
|
2000-10-31 16:17:33 +00:00
|
|
|
|
GSObjCZone(NSObject *object)
|
1998-10-15 05:03:16 +00:00
|
|
|
|
{
|
2001-06-06 15:18:28 +00:00
|
|
|
|
if (GSObjCClass(object) == NSConstantStringClass)
|
2000-10-09 04:41:18 +00:00
|
|
|
|
return NSDefaultMallocZone();
|
|
|
|
|
return NSZoneFromPointer(object);
|
1998-10-15 05:03:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-11-12 08:02:48 +00:00
|
|
|
|
inline NSObject *
|
|
|
|
|
NSAllocateObject (Class aClass, unsigned extraBytes, NSZone *zone)
|
1998-08-04 09:22:51 +00:00
|
|
|
|
{
|
|
|
|
|
id new = nil;
|
|
|
|
|
int size = aClass->instance_size + extraBytes;
|
|
|
|
|
if (CLS_ISCLASS (aClass))
|
|
|
|
|
new = NSZoneMalloc (zone, size);
|
|
|
|
|
if (new != nil)
|
|
|
|
|
{
|
|
|
|
|
memset (new, 0, size);
|
|
|
|
|
new->class_pointer = aClass;
|
|
|
|
|
#ifndef NDEBUG
|
2001-04-19 16:10:23 +00:00
|
|
|
|
GSDebugAllocationAdd(aClass, new);
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#endif
|
1998-10-15 05:03:16 +00:00
|
|
|
|
}
|
1998-08-04 09:22:51 +00:00
|
|
|
|
return new;
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-12 08:02:48 +00:00
|
|
|
|
inline void
|
|
|
|
|
NSDeallocateObject(NSObject *anObject)
|
1998-08-04 09:22:51 +00:00
|
|
|
|
{
|
|
|
|
|
if ((anObject!=nil) && CLS_ISCLASS(((id)anObject)->class_pointer))
|
|
|
|
|
{
|
|
|
|
|
NSZone *z = [anObject zone];
|
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2001-04-19 16:10:23 +00:00
|
|
|
|
GSDebugAllocationRemove(((id)anObject)->class_pointer, (id)anObject);
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#endif
|
|
|
|
|
((id)anObject)->class_pointer = (void*) 0xdeadface;
|
|
|
|
|
NSZoneFree(z, anObject);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* defined(REFCNT_LOCAL) || defined(CACHE_ZONE) */
|
|
|
|
|
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif /* GS_WITH_GC */
|
|
|
|
|
|
1998-08-04 09:22:51 +00:00
|
|
|
|
BOOL
|
|
|
|
|
NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone)
|
|
|
|
|
{
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
return YES;
|
|
|
|
|
#else
|
|
|
|
|
return (!requestedZone || requestedZone == NSDefaultMallocZone()
|
2000-10-31 16:17:33 +00:00
|
|
|
|
|| GSObjCZone(anObject) == requestedZone);
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif
|
1998-08-04 09:22:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The Class responsible for handling autorelease's. This does not
|
|
|
|
|
need mutex protection, since it is simply a pointer that gets read
|
|
|
|
|
and set. */
|
|
|
|
|
static id autorelease_class = nil;
|
2000-10-30 18:00:27 +00:00
|
|
|
|
static SEL autorelease_sel;
|
|
|
|
|
static IMP autorelease_imp;
|
1998-08-04 09:22:51 +00:00
|
|
|
|
|
|
|
|
|
/* When this is `YES', every call to release/autorelease, checks to
|
|
|
|
|
make sure isn't being set up to release itself too many times.
|
|
|
|
|
This does not need mutex protection. */
|
|
|
|
|
static BOOL double_release_check_enabled = NO;
|
|
|
|
|
|
1999-12-13 12:14:01 +00:00
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
@implementation NSObject
|
|
|
|
|
|
1999-12-13 12:14:01 +00:00
|
|
|
|
+ (void) _becomeMultiThreaded: (NSNotification)aNotification
|
|
|
|
|
{
|
|
|
|
|
if (retain_counts_gate == 0)
|
|
|
|
|
{
|
|
|
|
|
retain_counts_gate = objc_mutex_allocate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-04 10:17:03 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
+ (BOOL) requiresTypedMemory
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
1995-03-12 15:40:22 +00:00
|
|
|
|
if (self == [NSObject class])
|
|
|
|
|
{
|
2001-04-23 08:55:58 +00:00
|
|
|
|
extern void GSBuildStrings(); // See externs.m
|
|
|
|
|
extern const char* GSSetLocaleC(); // See GSLocale.m
|
|
|
|
|
|
2000-10-11 18:49:32 +00:00
|
|
|
|
#ifdef __MINGW__
|
|
|
|
|
// See libgnustep-base-entry.m
|
|
|
|
|
extern void gnustep_base_socket_init();
|
|
|
|
|
gnustep_base_socket_init();
|
|
|
|
|
#endif
|
|
|
|
|
|
1999-11-04 20:08:14 +00:00
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
|
// Manipulate the FPU to add the exception mask. (Fixes SIGFPE
|
|
|
|
|
// problems on *BSD)
|
|
|
|
|
|
2001-05-02 20:49:48 +00:00
|
|
|
|
{
|
|
|
|
|
volatile short cw;
|
1999-11-04 20:08:14 +00:00
|
|
|
|
|
2001-05-02 20:49:48 +00:00
|
|
|
|
__asm__ volatile ("fstcw (%0)" : : "g" (&cw));
|
|
|
|
|
cw |= 1; /* Mask 'invalid' exception */
|
|
|
|
|
__asm__ volatile ("fldcw (%0)" : : "g" (&cw));
|
|
|
|
|
}
|
1999-11-04 20:08:14 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2001-05-03 15:32:31 +00:00
|
|
|
|
GSSetLocaleC(""); // Set up locale from environment.
|
|
|
|
|
|
1997-09-13 17:52:31 +00:00
|
|
|
|
// Create the global lock
|
|
|
|
|
gnustep_global_lock = [[NSRecursiveLock alloc] init];
|
1999-09-28 19:35:09 +00:00
|
|
|
|
autorelease_class = [NSAutoreleasePool class];
|
2000-10-30 18:00:27 +00:00
|
|
|
|
autorelease_sel = @selector(addObject:);
|
1999-09-28 19:35:09 +00:00
|
|
|
|
autorelease_imp = [autorelease_class methodForSelector: autorelease_sel];
|
|
|
|
|
fastMallocClass = [_FastMallocBuffer class];
|
|
|
|
|
#if GS_WITH_GC == 0
|
|
|
|
|
#if !defined(REFCNT_LOCAL)
|
2002-02-02 07:10:51 +00:00
|
|
|
|
GSIMapInitWithZoneAndCapacity(&retain_counts,
|
|
|
|
|
NSDefaultMallocZone(), 1024);
|
1998-08-04 09:22:51 +00:00
|
|
|
|
#endif
|
1998-11-12 10:58:17 +00:00
|
|
|
|
fastMallocOffset = fastMallocClass->instance_size % ALIGN;
|
1999-09-28 19:35:09 +00:00
|
|
|
|
#else
|
|
|
|
|
fastMallocOffset = 0;
|
|
|
|
|
#endif
|
2001-06-06 15:18:28 +00:00
|
|
|
|
NSConstantStringClass = [NSString constantStringClass];
|
2000-07-03 11:47:17 +00:00
|
|
|
|
GSBuildStrings();
|
1999-12-13 12:14:01 +00:00
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
addObserver: self
|
|
|
|
|
selector: @selector(_becomeMultiThreaded:)
|
|
|
|
|
name: NSWillBecomeMultiThreadedNotification
|
|
|
|
|
object: nil];
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
1994-11-08 16:44:01 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id) alloc
|
|
|
|
|
{
|
1997-01-06 21:34:06 +00:00
|
|
|
|
return [self allocWithZone: NSDefaultMallocZone()];
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
1996-01-26 19:18:08 +00:00
|
|
|
|
return NSAllocateObject (self, 0, z);
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-07-15 12:48:14 +00:00
|
|
|
|
+ (id) copyWithZone: (NSZone*)z
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
1998-07-15 12:48:14 +00:00
|
|
|
|
return self;
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-07-15 12:48:14 +00:00
|
|
|
|
+ (id) new
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
1998-07-15 12:48:14 +00:00
|
|
|
|
return [[self alloc] init];
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
- (id) copy
|
|
|
|
|
{
|
1998-07-29 09:22:18 +00:00
|
|
|
|
return [(id)self copyWithZone: NULL];
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1996-01-26 19:18:08 +00:00
|
|
|
|
NSDeallocateObject (self);
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) free
|
1995-01-26 17:55:52 +00:00
|
|
|
|
{
|
1996-03-26 19:35:47 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
2000-06-30 11:59:59 +00:00
|
|
|
|
format: @"Use `dealloc' instead of `free' for %@.", self];
|
1995-01-26 17:55:52 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (id) mutableCopy
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
1998-07-29 09:22:18 +00:00
|
|
|
|
return [(id)self mutableCopyWithZone: NULL];
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-01 20:21:53 +00:00
|
|
|
|
+ (Class) superclass
|
|
|
|
|
{
|
1996-01-26 19:18:08 +00:00
|
|
|
|
return class_get_super_class (self);
|
1995-04-01 20:21:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (Class) superclass
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
1996-01-26 19:18:08 +00:00
|
|
|
|
return object_get_super_class (self);
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) instancesRespondToSelector: (SEL)aSelector
|
|
|
|
|
{
|
1998-11-26 13:21:37 +00:00
|
|
|
|
#if 0
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return (class_get_instance_method(self, aSelector) != METHOD_NULL);
|
1998-11-26 13:21:37 +00:00
|
|
|
|
#else
|
1998-11-27 13:27:58 +00:00
|
|
|
|
return __objc_responds_to((id)&self, aSelector);
|
1998-11-26 13:21:37 +00:00
|
|
|
|
#endif
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-27 17:25:42 +00:00
|
|
|
|
+ (BOOL) conformsToProtocol: (Protocol*)aProtocol
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
|
|
|
|
struct objc_protocol_list* proto_list;
|
|
|
|
|
|
2001-12-18 20:04:50 +00:00
|
|
|
|
for (proto_list = ((struct objc_class*)self)->protocols;
|
1996-05-31 16:12:24 +00:00
|
|
|
|
proto_list; proto_list = proto_list->next)
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
2001-12-18 20:04:50 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < proto_list->count; i++)
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
1995-04-01 17:48:49 +00:00
|
|
|
|
/* xxx We should add conformsToProtocol to Protocol class. */
|
1996-05-31 16:12:24 +00:00
|
|
|
|
if ([proto_list->list[i] conformsTo: aProtocol])
|
2001-12-18 20:04:50 +00:00
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-12-18 20:04:50 +00:00
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
if ([self superclass])
|
2001-12-18 20:04:50 +00:00
|
|
|
|
{
|
|
|
|
|
return [[self superclass] conformsToProtocol: aProtocol];
|
|
|
|
|
}
|
1994-11-08 16:44:01 +00:00
|
|
|
|
else
|
2001-12-18 20:04:50 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-27 17:25:42 +00:00
|
|
|
|
- (BOOL) conformsToProtocol: (Protocol*)aProtocol
|
|
|
|
|
{
|
|
|
|
|
return [[self class] conformsToProtocol:aProtocol];
|
|
|
|
|
}
|
|
|
|
|
|
1998-11-02 10:17:28 +00:00
|
|
|
|
+ (IMP) instanceMethodForSelector: (SEL)aSelector
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
1998-10-26 12:14:12 +00:00
|
|
|
|
/*
|
|
|
|
|
* Since 'self' is an class, get_imp() will get the instance method.
|
|
|
|
|
*/
|
|
|
|
|
return get_imp((Class)self, aSelector);
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
1998-10-26 12:14:12 +00:00
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
- (IMP) methodForSelector: (SEL)aSelector
|
|
|
|
|
{
|
1998-10-26 12:14:12 +00:00
|
|
|
|
/*
|
2000-10-31 16:17:33 +00:00
|
|
|
|
* If 'self' is an instance, GSObjCClass() will get the class,
|
1998-10-26 12:14:12 +00:00
|
|
|
|
* and get_imp() will get the instance method.
|
2000-10-31 16:17:33 +00:00
|
|
|
|
* If 'self' is a class, GSObjCClass() will get the meta-class,
|
1998-10-26 12:14:12 +00:00
|
|
|
|
* and get_imp() will get the class method.
|
|
|
|
|
*/
|
2000-10-31 16:17:33 +00:00
|
|
|
|
return get_imp(GSObjCClass(self), aSelector);
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-07-29 09:36:16 +00:00
|
|
|
|
+ (NSMethodSignature*) instanceMethodSignatureForSelector: (SEL)aSelector
|
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
struct objc_method* mth = class_get_instance_method(self, aSelector);
|
|
|
|
|
return mth ? [NSMethodSignature signatureWithObjCTypes:mth->method_types]
|
|
|
|
|
: nil;
|
1998-07-29 09:36:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
const char *types;
|
2001-03-07 21:21:10 +00:00
|
|
|
|
struct objc_method *mth;
|
2001-01-03 11:22:59 +00:00
|
|
|
|
|
2001-04-10 03:27:01 +00:00
|
|
|
|
if (aSelector == 0)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2001-03-07 21:21:10 +00:00
|
|
|
|
mth = (GSObjCIsInstance(self)
|
|
|
|
|
? class_get_instance_method(GSObjCClass(self), aSelector)
|
|
|
|
|
: class_get_class_method(GSObjCClass(self), aSelector));
|
|
|
|
|
if (mth == 0)
|
2001-04-10 03:27:01 +00:00
|
|
|
|
{
|
|
|
|
|
types = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
types = mth->method_types;
|
|
|
|
|
}
|
|
|
|
|
if (types == 0)
|
|
|
|
|
{
|
2001-08-28 18:45:17 +00:00
|
|
|
|
types = sel_get_type(aSelector);
|
2001-04-10 03:27:01 +00:00
|
|
|
|
}
|
|
|
|
|
if (types == 0)
|
2000-07-04 10:17:03 +00:00
|
|
|
|
{
|
2001-03-07 21:21:10 +00:00
|
|
|
|
return nil;
|
2000-07-04 10:17:03 +00:00
|
|
|
|
}
|
|
|
|
|
return [NSMethodSignature signatureWithObjCTypes: types];
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (NSString*) description
|
1995-01-26 17:55:52 +00:00
|
|
|
|
{
|
1999-12-13 12:14:01 +00:00
|
|
|
|
return [NSString stringWithFormat: @"<%s: %lx>",
|
2000-03-17 13:13:08 +00:00
|
|
|
|
object_get_class_name(self), (unsigned long)self];
|
1995-01-26 17:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
+ (NSString*) description
|
|
|
|
|
{
|
1999-12-13 12:14:01 +00:00
|
|
|
|
return [NSString stringWithCString: object_get_class_name(self)];
|
1998-12-18 17:05:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
+ (void) poseAsClass: (Class)aClassObject
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
1995-03-12 15:40:22 +00:00
|
|
|
|
class_pose_as(self, aClassObject);
|
1998-10-07 11:26:18 +00:00
|
|
|
|
/*
|
|
|
|
|
* We may have replaced a class in the cache, or may have replaced one
|
|
|
|
|
* which had cached methods, so we must rebuild the cache.
|
|
|
|
|
*/
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) doesNotRecognizeSelector: (SEL)aSelector
|
|
|
|
|
{
|
1996-09-17 14:33:30 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2002-01-31 15:41:47 +00:00
|
|
|
|
format: @"%s(%s) does not recognize %s",
|
|
|
|
|
object_get_class_name(self),
|
|
|
|
|
GSObjCIsInstance(self) ? "instance" : "class",
|
|
|
|
|
sel_get_name(aSelector)];
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (retval_t) forward:(SEL)aSel :(arglist_t)argFrame
|
|
|
|
|
{
|
1998-05-21 13:41:55 +00:00
|
|
|
|
NSInvocation *inv;
|
|
|
|
|
|
2000-10-24 11:58:25 +00:00
|
|
|
|
inv = AUTORELEASE([[NSInvocation alloc] initWithArgframe: argFrame
|
|
|
|
|
selector: aSel]);
|
1994-11-08 16:44:01 +00:00
|
|
|
|
[self forwardInvocation:inv];
|
1998-08-13 20:45:32 +00:00
|
|
|
|
return [inv returnFrame: argFrame];
|
1994-11-08 16:44:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) forwardInvocation: (NSInvocation*)anInvocation
|
|
|
|
|
{
|
|
|
|
|
[self doesNotRecognizeSelector:[anInvocation selector]];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1995-01-26 17:55:52 +00:00
|
|
|
|
- (id) awakeAfterUsingCoder: (NSCoder*)aDecoder
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-11 06:26:40 +00:00
|
|
|
|
- (Class) classForArchiver
|
|
|
|
|
{
|
|
|
|
|
return [self classForCoder];
|
|
|
|
|
}
|
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
- (Class) classForCoder
|
|
|
|
|
{
|
|
|
|
|
return [self class];
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-11 06:26:40 +00:00
|
|
|
|
- (Class) classForPortCoder
|
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
return [self classForCoder];
|
1998-10-11 06:26:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-22 10:02:39 +00:00
|
|
|
|
- (id) replacementObjectForArchiver: (NSArchiver*)anArchiver
|
1998-10-11 06:26:40 +00:00
|
|
|
|
{
|
|
|
|
|
return [self replacementObjectForCoder: (NSCoder*)anArchiver];
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (id) replacementObjectForCoder: (NSCoder*)anEncoder
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-11 06:26:40 +00:00
|
|
|
|
- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
|
|
|
|
|
{
|
2000-06-26 11:12:13 +00:00
|
|
|
|
static Class proxyClass = 0;
|
|
|
|
|
static IMP proxyImp = 0;
|
|
|
|
|
|
|
|
|
|
if (proxyImp == 0)
|
|
|
|
|
{
|
|
|
|
|
proxyClass = [NSDistantObject class];
|
2000-06-28 09:35:12 +00:00
|
|
|
|
/*
|
|
|
|
|
* use get_imp() because NSDistantObject doesn't implement
|
|
|
|
|
* methodForSelector:
|
|
|
|
|
*/
|
2000-10-31 16:17:33 +00:00
|
|
|
|
proxyImp = get_imp(GSObjCClass((id)proxyClass),
|
2000-06-28 09:35:12 +00:00
|
|
|
|
@selector(proxyWithLocal:connection:));
|
2000-06-26 11:12:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([aCoder isBycopy])
|
|
|
|
|
{
|
|
|
|
|
return self;
|
1998-10-11 06:26:40 +00:00
|
|
|
|
}
|
2000-06-26 11:12:13 +00:00
|
|
|
|
else if ([self isKindOfClass: proxyClass])
|
|
|
|
|
{
|
|
|
|
|
return self;
|
1998-10-11 06:26:40 +00:00
|
|
|
|
}
|
2000-06-26 11:12:13 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return (*proxyImp)(proxyClass, @selector(proxyWithLocal:connection:),
|
|
|
|
|
self, [aCoder connection]);
|
1998-10-11 06:26:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-26 19:18:08 +00:00
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
/* NSObject protocol */
|
|
|
|
|
|
1999-12-13 12:14:01 +00:00
|
|
|
|
- (id) autorelease
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#if GS_WITH_GC == 0
|
1995-08-04 20:52:07 +00:00
|
|
|
|
if (double_release_check_enabled)
|
|
|
|
|
{
|
|
|
|
|
unsigned release_count;
|
1997-10-28 14:34:49 +00:00
|
|
|
|
unsigned retain_count = [self retainCount];
|
1995-08-04 20:52:07 +00:00
|
|
|
|
release_count = [autorelease_class autoreleaseCountForObject:self];
|
|
|
|
|
if (release_count > retain_count)
|
1996-03-26 19:35:47 +00:00
|
|
|
|
[NSException
|
|
|
|
|
raise: NSGenericException
|
|
|
|
|
format: @"Autorelease would release object too many times.\n"
|
1996-03-26 20:59:42 +00:00
|
|
|
|
@"%d release(s) versus %d retain(s)", release_count, retain_count];
|
1995-08-04 20:52:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-25 07:56:22 +00:00
|
|
|
|
(*autorelease_imp)(autorelease_class, autorelease_sel, self);
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
+ (id) autorelease
|
1995-04-05 01:54:16 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1998-09-28 20:38:02 +00:00
|
|
|
|
+ (Class) class
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (Class) class
|
|
|
|
|
{
|
1995-03-23 03:31:30 +00:00
|
|
|
|
return object_get_class(self);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned) hash
|
|
|
|
|
{
|
|
|
|
|
return (unsigned)self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return (self == anObject);
|
|
|
|
|
}
|
|
|
|
|
|
1998-06-24 17:22:34 +00:00
|
|
|
|
+ (BOOL) isKindOfClass: (Class)aClass
|
|
|
|
|
{
|
1999-07-28 14:49:41 +00:00
|
|
|
|
if (aClass == [NSObject class])
|
|
|
|
|
return YES;
|
1998-06-24 17:22:34 +00:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (BOOL) isKindOfClass: (Class)aClass
|
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
Class class = GSObjCClass(self);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
2000-10-31 16:17:33 +00:00
|
|
|
|
return GSObjCIsKindOf(class, aClass);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-06-24 17:22:34 +00:00
|
|
|
|
+ (BOOL) isMemberOfClass: (Class)aClass
|
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
return (self == aClass) ? YES : NO;
|
1998-06-24 17:22:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (BOOL) isMemberOfClass: (Class)aClass
|
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
return (GSObjCClass(self) == aClass) ? YES : NO;
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isProxy
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) performSelector: (SEL)aSelector
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
1998-10-26 12:14:12 +00:00
|
|
|
|
IMP msg;
|
|
|
|
|
|
|
|
|
|
if (aSelector == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nul selector passed to %s", sel_get_name(_cmd)];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-31 16:17:33 +00:00
|
|
|
|
msg = get_imp(GSObjCClass(self), aSelector);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
if (!msg)
|
1996-03-26 20:59:42 +00:00
|
|
|
|
{
|
1998-10-26 12:14:12 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"invalid selector passed to %s", sel_get_name(_cmd)];
|
1996-03-26 20:59:42 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return (*msg)(self, aSelector);
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) performSelector: (SEL)aSelector withObject: (id) anObject
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
1998-10-26 12:14:12 +00:00
|
|
|
|
IMP msg;
|
|
|
|
|
|
|
|
|
|
if (aSelector == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nul selector passed to %s", sel_get_name(_cmd)];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-31 16:17:33 +00:00
|
|
|
|
msg = get_imp(GSObjCClass(self), aSelector);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
if (!msg)
|
1996-03-26 20:59:42 +00:00
|
|
|
|
{
|
1998-10-26 12:14:12 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"invalid selector passed to %s", sel_get_name(_cmd)];
|
1996-03-26 20:59:42 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-10-26 12:14:12 +00:00
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return (*msg)(self, aSelector, anObject);
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) performSelector: (SEL)aSelector
|
|
|
|
|
withObject: (id) object1
|
|
|
|
|
withObject: (id) object2
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
1998-10-26 12:14:12 +00:00
|
|
|
|
IMP msg;
|
|
|
|
|
|
|
|
|
|
if (aSelector == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nul selector passed to %s", sel_get_name(_cmd)];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2000-10-31 16:17:33 +00:00
|
|
|
|
msg = get_imp(GSObjCClass(self), aSelector);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
if (!msg)
|
1996-03-26 20:59:42 +00:00
|
|
|
|
{
|
1998-10-26 12:14:12 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"invalid selector passed to %s", sel_get_name(_cmd)];
|
1996-03-26 20:59:42 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
1998-10-26 12:14:12 +00:00
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return (*msg)(self, aSelector, object1, object2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (oneway void) release
|
|
|
|
|
{
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#if GS_WITH_GC == 0
|
1995-08-04 20:52:07 +00:00
|
|
|
|
if (double_release_check_enabled)
|
|
|
|
|
{
|
|
|
|
|
unsigned release_count;
|
1997-10-28 14:34:49 +00:00
|
|
|
|
unsigned retain_count = [self retainCount];
|
1995-08-04 20:52:07 +00:00
|
|
|
|
release_count = [autorelease_class autoreleaseCountForObject:self];
|
1997-10-28 14:34:49 +00:00
|
|
|
|
if (release_count >= retain_count)
|
1996-03-26 19:35:47 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"Release would release object too many times."];
|
1995-08-04 20:52:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
if (NSDecrementExtraRefCountWasZero(self))
|
1999-12-15 17:31:01 +00:00
|
|
|
|
{
|
|
|
|
|
if (deallocNotifications == NO || [self _dealloc] == YES)
|
|
|
|
|
{
|
|
|
|
|
[self dealloc];
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-05 01:54:16 +00:00
|
|
|
|
+ (oneway void) release
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (BOOL) respondsToSelector: (SEL)aSelector
|
|
|
|
|
{
|
1998-11-27 13:27:58 +00:00
|
|
|
|
return __objc_responds_to(self, aSelector);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) retain
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#if GS_WITH_GC == 0
|
1995-03-24 20:09:36 +00:00
|
|
|
|
NSIncrementExtraRefCount(self);
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
+ (id) retain
|
1995-04-05 01:54:16 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
- (unsigned) retainCount
|
|
|
|
|
{
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
return UINT_MAX;
|
|
|
|
|
#else
|
1999-05-21 18:14:48 +00:00
|
|
|
|
return NSExtraRefCount(self) + 1;
|
1999-01-28 17:21:03 +00:00
|
|
|
|
#endif
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-05 01:54:16 +00:00
|
|
|
|
+ (unsigned) retainCount
|
|
|
|
|
{
|
|
|
|
|
return UINT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) self
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (NSZone*) zone
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
return GSObjCZone(self);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-09 01:53:53 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
1994-11-08 16:44:01 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
+ (int) version
|
1998-09-28 20:38:02 +00:00
|
|
|
|
{
|
|
|
|
|
return class_get_version(self);
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
+ (id) setVersion: (int)aVersion
|
1998-09-28 20:38:02 +00:00
|
|
|
|
{
|
1998-10-09 13:54:54 +00:00
|
|
|
|
if (aVersion < 0)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"%s +setVersion: may not set a negative version",
|
|
|
|
|
object_get_class_name(self)];
|
1998-09-28 20:38:02 +00:00
|
|
|
|
class_set_version(self, aVersion);
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1994-11-08 16:44:01 +00:00
|
|
|
|
@end
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
@implementation NSObject (NEXTSTEP)
|
|
|
|
|
|
|
|
|
|
/* NEXTSTEP Object class compatibility */
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- error: (const char *)aString, ...
|
1995-01-26 17:55:52 +00:00
|
|
|
|
{
|
1995-03-12 15:40:22 +00:00
|
|
|
|
#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),
|
2000-10-31 16:17:33 +00:00
|
|
|
|
GSObjCIsInstance(self)?"instance":"class",
|
1995-03-12 15:40:22 +00:00
|
|
|
|
(aString!=NULL)?aString:"");
|
|
|
|
|
va_start(ap, aString);
|
1996-09-07 21:07:27 +00:00
|
|
|
|
/* xxx What should `code' argument be? Current 0. */
|
|
|
|
|
objc_verror (self, 0, fmt, ap);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
va_end(ap);
|
|
|
|
|
return nil;
|
|
|
|
|
#undef FMT
|
1995-01-26 17:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-02-24 16:38:43 +00:00
|
|
|
|
- (const char *) name
|
1995-01-26 17:55:52 +00:00
|
|
|
|
{
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return object_get_class_name(self);
|
1995-01-26 17:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (BOOL) isKindOf: (Class)aClassObject
|
1995-01-26 17:55:52 +00:00
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
return [self isKindOfClass: aClassObject];
|
1995-01-26 17:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (BOOL) isMemberOf: (Class)aClassObject
|
1995-01-26 17:55:52 +00:00
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
return [self isMemberOfClass: aClassObject];
|
1995-01-26 17:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
+ (BOOL) instancesRespondTo: (SEL)aSel
|
1995-01-26 17:55:52 +00:00
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
return [self instancesRespondToSelector: aSel];
|
1995-01-26 17:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (BOOL) respondsTo: (SEL)aSel
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
return [self respondsToSelector: aSel];
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) conformsTo: (Protocol*)aProtocol
|
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
return [self conformsToProtocol: aProtocol];
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-27 17:25:42 +00:00
|
|
|
|
- (BOOL) conformsTo: (Protocol*)aProtocol
|
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
return [self conformsToProtocol: aProtocol];
|
1995-03-27 17:25:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (retval_t) performv: (SEL)aSel :(arglist_t)argFrame
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return objc_msg_sendv(self, aSel, argFrame);
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
+ (IMP) instanceMethodFor: (SEL)aSel
|
1995-01-26 17:55:52 +00:00
|
|
|
|
{
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return [self instanceMethodForSelector:aSel];
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-28 09:35:12 +00:00
|
|
|
|
+ (NSMethodSignature*) instanceMethodSignatureForSelector: (SEL)aSelector
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2000-06-28 09:35:12 +00:00
|
|
|
|
struct objc_method* mth = class_get_instance_method(self, aSelector);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2000-06-28 09:35:12 +00:00
|
|
|
|
return mth ? [NSMethodSignature signatureWithObjCTypes:mth->method_types]
|
|
|
|
|
: nil;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (IMP) methodFor: (SEL)aSel
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
return [self methodForSelector: aSel];
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
+ (id) poseAs: (Class)aClassObject
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2000-06-30 11:59:59 +00:00
|
|
|
|
[self poseAsClass: aClassObject];
|
1995-03-12 15:40:22 +00:00
|
|
|
|
return self;
|
1995-01-26 17:55:52 +00:00
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) notImplemented: (SEL)aSel
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
1996-03-26 20:59:42 +00:00
|
|
|
|
[NSException
|
|
|
|
|
raise: NSGenericException
|
2002-01-31 15:41:47 +00:00
|
|
|
|
format: @"method %s not implemented in %s(%s)", sel_get_name(aSel),
|
|
|
|
|
object_get_class_name(self),
|
|
|
|
|
GSObjCIsInstance(self) ? "instance" : "class"];
|
1996-03-26 20:59:42 +00:00
|
|
|
|
return nil;
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) doesNotRecognize: (SEL)aSel
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
1996-03-26 20:59:42 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
2002-01-31 15:41:47 +00:00
|
|
|
|
format: @"%s(%s) does not recognize %s",
|
|
|
|
|
object_get_class_name(self),
|
|
|
|
|
GSObjCIsInstance(self) ? "instance" : "class",
|
|
|
|
|
sel_get_name(aSel)];
|
1996-03-26 20:59:42 +00:00
|
|
|
|
return nil;
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) perform: (SEL)sel with: (id)anObject
|
1995-03-23 03:31:30 +00:00
|
|
|
|
{
|
1998-09-28 20:38:02 +00:00
|
|
|
|
return [self performSelector:sel withObject:anObject];
|
1995-03-23 03:31:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) perform: (SEL)sel with: (id)anObject with: (id)anotherObject
|
1995-04-03 01:32:58 +00:00
|
|
|
|
{
|
1998-09-28 20:38:02 +00:00
|
|
|
|
return [self performSelector:sel withObject:anObject
|
|
|
|
|
withObject:anotherObject];
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 15:40:22 +00:00
|
|
|
|
@end
|
|
|
|
|
|
1996-07-15 18:41:44 +00:00
|
|
|
|
|
2000-11-27 22:26:08 +00:00
|
|
|
|
|
2000-12-02 21:36:56 +00:00
|
|
|
|
#include <Foundation/NSValue.h>
|
2000-11-27 22:26:08 +00:00
|
|
|
|
#include <Foundation/NSKeyValueCoding.h>
|
|
|
|
|
#include <Foundation/NSNull.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSObject (KeyValueCoding)
|
|
|
|
|
|
2000-12-02 21:36:56 +00:00
|
|
|
|
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
|
2001-01-03 11:22:59 +00:00
|
|
|
|
format: @"key-value get method has wrong number of args"];
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
type = [sig methodReturnType];
|
|
|
|
|
}
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (type == NULL)
|
2000-12-02 21:36:56 +00:00
|
|
|
|
{
|
2001-05-06 15:47:01 +00:00
|
|
|
|
return [self handleQueryWithUnboundKey: key];
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
id val = nil;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
|
|
|
|
case _C_CLASS:
|
|
|
|
|
{
|
|
|
|
|
id v;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(id *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(char *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(unsigned char *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(short *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(unsigned short *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(int *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(unsigned int *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(long *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(unsigned long *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(long long *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(unsigned long long *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(float *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
v = *(double *)((char *)self + off);
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
double (*imp)(id, SEL) =
|
|
|
|
|
(double (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
v = (*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = [NSNumber numberWithDouble: v];
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2002-01-07 15:34:20 +00:00
|
|
|
|
case _C_VOID:
|
|
|
|
|
{
|
|
|
|
|
void (*imp)(id, SEL) =
|
|
|
|
|
(void (*)(id, SEL))[self methodForSelector: sel];
|
|
|
|
|
|
|
|
|
|
(*imp)(self, sel);
|
|
|
|
|
}
|
|
|
|
|
val = nil;
|
|
|
|
|
break;
|
|
|
|
|
|
2000-12-02 21:36:56 +00:00
|
|
|
|
default:
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2001-01-03 11:22:59 +00:00
|
|
|
|
format: @"key-value get method has unsupported type"];
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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];
|
|
|
|
|
}
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (type == NULL)
|
2000-12-02 21:36:56 +00:00
|
|
|
|
{
|
|
|
|
|
[self handleTakeValue: val forUnboundKey: key];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
|
|
|
|
case _C_CLASS:
|
|
|
|
|
{
|
|
|
|
|
id v = val;
|
|
|
|
|
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
id *ptr = (id *)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
[*ptr autorelease];
|
|
|
|
|
*ptr = [v retain];
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
char *ptr = (char *)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
unsigned char *ptr = (unsigned char*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
short *ptr = (short*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
unsigned short *ptr = (unsigned short*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
int *ptr = (int*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
unsigned int *ptr = (unsigned int*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
long *ptr = (long*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
unsigned long *ptr = (unsigned long*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
long long *ptr = (long long*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
unsigned long long *ptr = (unsigned long long*)((char*)self +
|
|
|
|
|
off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
float *ptr = (float*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
double *ptr = (double*)((char *)self + off);
|
|
|
|
|
|
|
|
|
|
*ptr = v;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
}
|
|
|
|
|
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"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-27 22:26:08 +00:00
|
|
|
|
+ (BOOL) accessInstanceVariablesDirectly
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) useStoredAccessor
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) handleQueryWithUnboundKey: (NSString*)aKey
|
|
|
|
|
{
|
2001-01-03 11:22:59 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"%@ -- %@ 0x%x: Unable to find value for key \"%@\"", NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, aKey];
|
|
|
|
|
|
2000-11-27 22:26:08 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) handleTakeValue: (id)anObject forUnboundKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSGenericException
|
2001-01-03 11:22:59 +00:00
|
|
|
|
format: @"%@ -- %@ 0x%x: Unable set value \"%@\" for key \"%@\"", NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, anObject, aKey];
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) storedValueForKey: (NSString*)aKey
|
|
|
|
|
{
|
2000-11-30 12:19:50 +00:00
|
|
|
|
SEL sel = 0;
|
2001-01-03 11:22:59 +00:00
|
|
|
|
const char *type = NULL;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
unsigned size;
|
|
|
|
|
unsigned off;
|
2000-11-30 12:19:50 +00:00
|
|
|
|
NSString *name;
|
2001-04-24 12:28:07 +00:00
|
|
|
|
NSString *cap;
|
2000-11-27 22:26:08 +00:00
|
|
|
|
|
|
|
|
|
if ([[self class] useStoredAccessor] == NO)
|
|
|
|
|
{
|
|
|
|
|
return [self valueForKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-24 12:28:07 +00:00
|
|
|
|
size = [aKey length];
|
|
|
|
|
if (size < 1)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"storedValueForKey: ... empty key"];
|
|
|
|
|
}
|
|
|
|
|
cap = [[aKey substringToIndex: 1] uppercaseString];
|
|
|
|
|
if (size > 1)
|
|
|
|
|
{
|
|
|
|
|
cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name = [NSString stringWithFormat: @"_get%@", cap];
|
2000-11-30 12:19:50 +00:00
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-11-30 12:19:50 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"_%@", aKey];
|
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-11-30 12:19:50 +00:00
|
|
|
|
{
|
|
|
|
|
sel = 0;
|
|
|
|
|
}
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
2000-11-30 12:19:50 +00:00
|
|
|
|
if (sel == 0)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-11-30 12:19:50 +00:00
|
|
|
|
if ([[self class] accessInstanceVariablesDirectly] == YES)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-11-30 12:19:50 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"_%@", aKey];
|
2000-12-02 21:36:56 +00:00
|
|
|
|
if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
|
2000-11-30 12:19:50 +00:00
|
|
|
|
{
|
|
|
|
|
name = aKey;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
GSInstanceVariableInfo(self, name, &type, &size, &off);
|
2000-11-30 12:19:50 +00:00
|
|
|
|
}
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (type == NULL)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2001-04-24 12:28:07 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"get%@", cap];
|
2000-11-30 12:19:50 +00:00
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-11-30 12:19:50 +00:00
|
|
|
|
{
|
|
|
|
|
name = aKey;
|
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-11-30 12:19:50 +00:00
|
|
|
|
{
|
|
|
|
|
sel = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-12-02 21:36:56 +00:00
|
|
|
|
return GSGetValue(self, aKey, sel, type, size, off);
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey
|
|
|
|
|
{
|
2000-12-02 21:36:56 +00:00
|
|
|
|
SEL sel;
|
|
|
|
|
const char *type;
|
|
|
|
|
unsigned size;
|
|
|
|
|
unsigned off;
|
|
|
|
|
NSString *cap;
|
2000-12-02 11:47:30 +00:00
|
|
|
|
NSString *name;
|
2000-11-27 22:26:08 +00:00
|
|
|
|
|
|
|
|
|
if ([[self class] useStoredAccessor] == NO)
|
|
|
|
|
{
|
|
|
|
|
[self takeValue: anObject forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-24 12:28:07 +00:00
|
|
|
|
size = [aKey length];
|
|
|
|
|
if (size < 1)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"takeStoredValue:forKey: ... empty key"];
|
|
|
|
|
}
|
|
|
|
|
cap = [[aKey substringToIndex: 1] uppercaseString];
|
|
|
|
|
if (size > 1)
|
|
|
|
|
{
|
|
|
|
|
cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]];
|
|
|
|
|
}
|
|
|
|
|
|
2000-12-02 21:36:56 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"_set%@:", cap];
|
2001-01-03 11:22:59 +00:00
|
|
|
|
type = NULL;
|
2000-12-02 11:47:30 +00:00
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-12-02 11:47:30 +00:00
|
|
|
|
sel = 0;
|
|
|
|
|
if ([[self class] accessInstanceVariablesDirectly] == YES)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-12-02 11:47:30 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"_%@", aKey];
|
2000-12-02 21:36:56 +00:00
|
|
|
|
if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
|
2000-12-02 11:47:30 +00:00
|
|
|
|
{
|
|
|
|
|
name = aKey;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
GSInstanceVariableInfo(self, name, &type, &size, &off);
|
2000-12-02 11:47:30 +00:00
|
|
|
|
}
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (type == NULL)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-12-02 21:36:56 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"set%@:", cap];
|
2000-12-02 11:47:30 +00:00
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-12-02 11:47:30 +00:00
|
|
|
|
{
|
|
|
|
|
sel = 0;
|
|
|
|
|
}
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-03 11:22:59 +00:00
|
|
|
|
GSSetValue(self, aKey, anObject, sel, type, size, off);
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) takeValue: (id)anObject forKey: (NSString*)aKey
|
|
|
|
|
{
|
2000-12-02 21:36:56 +00:00
|
|
|
|
SEL sel;
|
|
|
|
|
const char *type;
|
|
|
|
|
unsigned size;
|
|
|
|
|
unsigned off;
|
|
|
|
|
NSString *cap;
|
|
|
|
|
NSString *name;
|
2000-11-27 22:26:08 +00:00
|
|
|
|
|
2001-04-24 12:28:07 +00:00
|
|
|
|
size = [aKey length];
|
|
|
|
|
if (size < 1)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"takeValue:forKey: ... empty key"];
|
|
|
|
|
}
|
|
|
|
|
cap = [[aKey substringToIndex: 1] uppercaseString];
|
|
|
|
|
if (size > 1)
|
|
|
|
|
{
|
|
|
|
|
cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]];
|
|
|
|
|
}
|
|
|
|
|
|
2000-12-02 21:36:56 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"set%@:", cap];
|
2001-01-03 11:22:59 +00:00
|
|
|
|
type = NULL;
|
2000-12-02 11:47:30 +00:00
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-12-02 21:36:56 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"_set%@:", cap];
|
2000-12-02 11:47:30 +00:00
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-12-02 11:47:30 +00:00
|
|
|
|
{
|
|
|
|
|
sel = 0;
|
|
|
|
|
if ([[self class] accessInstanceVariablesDirectly] == YES)
|
|
|
|
|
{
|
|
|
|
|
name = [NSString stringWithFormat: @"_%@", aKey];
|
2000-12-02 21:36:56 +00:00
|
|
|
|
if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
|
2000-12-02 11:47:30 +00:00
|
|
|
|
{
|
|
|
|
|
name = aKey;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
GSInstanceVariableInfo(self, name, &type, &size, &off);
|
2000-12-02 11:47:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-03 11:22:59 +00:00
|
|
|
|
GSSetValue(self, aKey, anObject, sel, type, size, off);
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) takeValue: (id)anObject forKeyPath: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
NSArray *keys = [aKey componentsSeparatedByString: @"."];
|
|
|
|
|
id obj = self;
|
|
|
|
|
unsigned count = [keys count];
|
|
|
|
|
unsigned pos;
|
|
|
|
|
|
|
|
|
|
for (pos = 0; pos + 1 < count; pos++)
|
|
|
|
|
{
|
|
|
|
|
obj = [obj valueForKey: [keys objectAtIndex: pos]];
|
|
|
|
|
}
|
|
|
|
|
if (pos < count)
|
|
|
|
|
{
|
|
|
|
|
[obj takeValue: anObject forKey: [keys objectAtIndex: pos]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) takeValuesFromDictionary: (NSDictionary*)aDictionary
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *enumerator = [aDictionary keyEnumerator];
|
|
|
|
|
NSNull *null = [NSNull null];
|
|
|
|
|
NSString *key;
|
|
|
|
|
|
|
|
|
|
while ((key = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
id obj = [aDictionary objectForKey: key];
|
|
|
|
|
|
|
|
|
|
if (obj == null)
|
|
|
|
|
{
|
|
|
|
|
obj = nil;
|
|
|
|
|
}
|
|
|
|
|
[self takeValue: obj forKey: key];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) unableToSetNilForKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2001-01-03 11:22:59 +00:00
|
|
|
|
format: @"%@ -- %@ 0x%x: Given nil value to set for key \"%@\"", NSStringFromSelector(_cmd), NSStringFromClass([self class]), self, aKey];
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) valueForKey: (NSString*)aKey
|
|
|
|
|
{
|
2000-12-02 11:47:30 +00:00
|
|
|
|
SEL sel = 0;
|
2001-04-24 12:28:07 +00:00
|
|
|
|
NSString *cap;
|
2000-12-02 11:47:30 +00:00
|
|
|
|
NSString *name = nil;
|
2001-01-03 11:22:59 +00:00
|
|
|
|
const char *type = NULL;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
unsigned size;
|
|
|
|
|
unsigned off;
|
2000-11-27 22:26:08 +00:00
|
|
|
|
|
2001-04-24 12:28:07 +00:00
|
|
|
|
size = [aKey length];
|
|
|
|
|
if (size < 1)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"valueForKey: ... empty key"];
|
|
|
|
|
}
|
|
|
|
|
cap = [[aKey substringToIndex: 1] uppercaseString];
|
|
|
|
|
if (size > 1)
|
|
|
|
|
{
|
|
|
|
|
cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name = [@"get" stringByAppendingString: cap];
|
2000-12-02 11:47:30 +00:00
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-12-02 11:47:30 +00:00
|
|
|
|
name = aKey;
|
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-12-02 11:47:30 +00:00
|
|
|
|
{
|
2001-04-24 12:28:07 +00:00
|
|
|
|
name = [@"_get" stringByAppendingString: cap];
|
2000-12-02 11:47:30 +00:00
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-12-02 11:47:30 +00:00
|
|
|
|
{
|
|
|
|
|
name = [NSString stringWithFormat: @"_%@", aKey];
|
|
|
|
|
sel = NSSelectorFromString(name);
|
2001-01-03 11:22:59 +00:00
|
|
|
|
if (sel == 0 || [self respondsToSelector: sel] == NO)
|
2000-12-02 11:47:30 +00:00
|
|
|
|
{
|
|
|
|
|
sel = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-12-02 11:47:30 +00:00
|
|
|
|
if (sel == 0 && [[self class] accessInstanceVariablesDirectly] == YES)
|
2000-11-27 22:26:08 +00:00
|
|
|
|
{
|
2000-12-02 11:47:30 +00:00
|
|
|
|
name = [NSString stringWithFormat: @"_%@", aKey];
|
2000-12-02 21:36:56 +00:00
|
|
|
|
if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
|
2000-12-02 11:47:30 +00:00
|
|
|
|
{
|
|
|
|
|
name = aKey;
|
2000-12-02 21:36:56 +00:00
|
|
|
|
GSInstanceVariableInfo(self, name, &type, &size, &off);
|
2000-12-02 11:47:30 +00:00
|
|
|
|
}
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
2000-12-02 11:47:30 +00:00
|
|
|
|
|
2000-12-02 21:36:56 +00:00
|
|
|
|
return GSGetValue(self, aKey, sel, type, size, off);
|
2000-11-27 22:26:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) valueForKeyPath: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
NSArray *keys = [aKey componentsSeparatedByString: @"."];
|
|
|
|
|
id obj = self;
|
|
|
|
|
unsigned count = [keys count];
|
|
|
|
|
unsigned pos;
|
|
|
|
|
|
|
|
|
|
for (pos = 0; pos < count; pos++)
|
|
|
|
|
{
|
|
|
|
|
obj = [obj valueForKey: [keys objectAtIndex: pos]];
|
|
|
|
|
}
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSDictionary*) valuesForKeys: (NSArray*)keys
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *dict;
|
|
|
|
|
NSNull *null = [NSNull null];
|
|
|
|
|
unsigned count = [keys count];
|
|
|
|
|
unsigned pos;
|
|
|
|
|
|
|
|
|
|
dict = [NSMutableDictionary dictionaryWithCapacity: count];
|
|
|
|
|
for (pos = 0; pos < count; pos++)
|
|
|
|
|
{
|
|
|
|
|
NSString *key = [keys objectAtIndex: pos];
|
|
|
|
|
id val = [self valueForKey: key];
|
|
|
|
|
|
|
|
|
|
if (val == nil)
|
|
|
|
|
{
|
|
|
|
|
val = null;
|
|
|
|
|
}
|
|
|
|
|
[dict setObject: val forKey: key];
|
|
|
|
|
}
|
|
|
|
|
return AUTORELEASE([dict copy]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-01-06 11:26:49 +00:00
|
|
|
|
@implementation NSObject (GNU)
|
1995-03-12 15:40:22 +00:00
|
|
|
|
|
|
|
|
|
/* GNU Object class compatibility */
|
|
|
|
|
|
1995-03-12 19:29:37 +00:00
|
|
|
|
+ (void) setAutoreleaseClass: (Class)aClass
|
|
|
|
|
{
|
|
|
|
|
autorelease_class = aClass;
|
1998-10-25 07:56:22 +00:00
|
|
|
|
autorelease_imp = [self instanceMethodForSelector: autorelease_sel];
|
1995-03-12 19:29:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (Class) autoreleaseClass
|
|
|
|
|
{
|
|
|
|
|
return autorelease_class;
|
|
|
|
|
}
|
|
|
|
|
|
1995-08-04 20:52:07 +00:00
|
|
|
|
+ (void) enableDoubleReleaseCheck: (BOOL)enable
|
|
|
|
|
{
|
|
|
|
|
double_release_check_enabled = enable;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-06 11:26:49 +00:00
|
|
|
|
- (int) compare: (id)anObject
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2002-01-06 11:26:49 +00:00
|
|
|
|
if (anObject == self)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
return NSOrderedSame;
|
|
|
|
|
}
|
2002-01-06 11:26:49 +00:00
|
|
|
|
if (anObject == nil)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nil argument for compare:"];
|
|
|
|
|
}
|
2002-01-06 11:26:49 +00:00
|
|
|
|
if ([self isEqual: anObject])
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
return NSOrderedSame;
|
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
// Ordering objects by their address is pretty useless,
|
|
|
|
|
// so subclasses should override this is some useful way.
|
2002-01-06 11:26:49 +00:00
|
|
|
|
if (self > anObject)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
return NSOrderedDescending;
|
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
else
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
return NSOrderedAscending;
|
|
|
|
|
}
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-01-06 11:26:49 +00:00
|
|
|
|
- (NSString*) descriptionWithLocale: (NSDictionary*)aLocale
|
|
|
|
|
{
|
|
|
|
|
return [self description];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSString*) descriptionWithLocale: (NSDictionary*)aLocale
|
|
|
|
|
{
|
|
|
|
|
return [self description];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) descriptionWithLocale: (NSDictionary*)aLocale
|
|
|
|
|
indent: (unsigned)level
|
|
|
|
|
{
|
|
|
|
|
return [self descriptionWithLocale: aLocale];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSString*) descriptionWithLocale: (NSDictionary*)aLocale
|
|
|
|
|
indent: (unsigned)level
|
|
|
|
|
{
|
|
|
|
|
return [self descriptionWithLocale: aLocale];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) descriptionWithLocale: (NSDictionary*)aLocale
|
|
|
|
|
indent: (unsigned)level
|
|
|
|
|
to: (id<GNUDescriptionDestination>)output
|
|
|
|
|
{
|
|
|
|
|
[output appendString:
|
|
|
|
|
[(id)self descriptionWithLocale: aLocale indent: level]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) descriptionWithLocale: (NSDictionary*)aLocale
|
|
|
|
|
indent: (unsigned)level
|
|
|
|
|
to: (id<GNUDescriptionDestination>)output
|
|
|
|
|
{
|
|
|
|
|
[output appendString:
|
|
|
|
|
[(id)self descriptionWithLocale: aLocale indent: level]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) deallocNotificationsActive
|
|
|
|
|
{
|
|
|
|
|
return deallocNotifications;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setDeallocNotificationsActive: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
deallocNotifications = flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) _dealloc
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (BOOL) isMetaClass
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (BOOL) isClass
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return object_is_class(self);
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (BOOL) isInstance
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
return GSObjCIsInstance(self);
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (BOOL) isMemberOfClassNamed: (const char*)aClassName
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return ((aClassName!=NULL)
|
2000-10-31 16:17:33 +00:00
|
|
|
|
&&!strcmp(GSObjCName(GSObjCClass(self)), aClassName));
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
+ (struct objc_method_description *) descriptionForInstanceMethod: (SEL)aSel
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return ((struct objc_method_description *)
|
|
|
|
|
class_get_instance_method(self, aSel));
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (struct objc_method_description *) descriptionForMethod: (SEL)aSel
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
return ((struct objc_method_description *)
|
2000-10-31 16:17:33 +00:00
|
|
|
|
(GSObjCIsInstance(self)
|
|
|
|
|
?class_get_instance_method(GSObjCClass(self), aSel)
|
|
|
|
|
:class_get_class_method(GSObjCClass(self), aSel)));
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (Class) transmuteClassTo: (Class)aClassObject
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
if (GSObjCIsInstance(self) == YES)
|
1995-03-12 15:40:22 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (id) subclassResponsibility: (SEL)aSel
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2000-10-24 11:58:25 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
2002-01-31 15:41:47 +00:00
|
|
|
|
format: @"subclass %s(%s) should override %s",
|
|
|
|
|
object_get_class_name(self),
|
|
|
|
|
GSObjCIsInstance(self) ? "instance" : "class",
|
|
|
|
|
sel_get_name(aSel)];
|
1996-03-26 20:59:42 +00:00
|
|
|
|
return nil;
|
1995-03-12 15:40:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
- (id) shouldNotImplement: (SEL)aSel
|
1995-03-12 19:29:37 +00:00
|
|
|
|
{
|
1996-03-26 20:59:42 +00:00
|
|
|
|
[NSException
|
|
|
|
|
raise: NSGenericException
|
2002-01-31 15:41:47 +00:00
|
|
|
|
format: @"%s(%s) should not implement %s",
|
|
|
|
|
object_get_class_name(self),
|
|
|
|
|
GSObjCIsInstance(self) ? "instance" : "class",
|
|
|
|
|
sel_get_name(aSel)];
|
1996-03-26 20:59:42 +00:00
|
|
|
|
return nil;
|
1995-03-12 19:29:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-17 13:13:08 +00:00
|
|
|
|
+ (int) streamVersion: (TypedStream*)aStream
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
2001-08-28 18:45:17 +00:00
|
|
|
|
#ifndef NeXT_RUNTIME
|
1995-03-12 15:40:22 +00:00
|
|
|
|
if (aStream->mode == OBJC_READONLY)
|
|
|
|
|
return objc_get_stream_class_version (aStream, self);
|
|
|
|
|
else
|
2001-08-28 18:45:17 +00:00
|
|
|
|
#endif
|
1995-03-12 15:40:22 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) read: (TypedStream*)aStream
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
// [super read: aStream];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) write: (TypedStream*)aStream
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
// [super write: aStream];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) awake
|
1995-03-12 15:40:22 +00:00
|
|
|
|
{
|
|
|
|
|
// [super awake];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
1998-11-12 10:58:17 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Stuff for temporary memory management.
|
|
|
|
|
*/
|
|
|
|
|
@interface _FastMallocBuffer : NSObject
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation _FastMallocBuffer
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Function for giving us the fastest possible allocation of memory to
|
|
|
|
|
* be used for temporary storage.
|
|
|
|
|
*/
|
|
|
|
|
void *
|
|
|
|
|
_fastMallocBuffer(unsigned size)
|
|
|
|
|
{
|
|
|
|
|
_FastMallocBuffer *o;
|
|
|
|
|
|
|
|
|
|
o = (_FastMallocBuffer*)NSAllocateObject(fastMallocClass,
|
|
|
|
|
size + fastMallocOffset, NSDefaultMallocZone());
|
|
|
|
|
(*autorelease_imp)(autorelease_class, autorelease_sel, o);
|
|
|
|
|
return ((void*)&o[1])+fastMallocOffset;
|
|
|
|
|
}
|
|
|
|
|
|
2000-02-24 22:16:53 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Stuff for compatibility with 'Object' derived classes.
|
|
|
|
|
*/
|
|
|
|
|
@interface Object (NSObjectCompat)
|
|
|
|
|
+ (void) release;
|
|
|
|
|
+ (id) retain;
|
|
|
|
|
- (void) release;
|
|
|
|
|
- (id) retain;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation Object (NSObjectCompat)
|
|
|
|
|
+ (void) release
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
+ (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
- (void) release
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|