mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
Efficiency hacks - avoiding objc messaging overheads.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3032 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
37b25563c6
commit
1b0bf3c664
7 changed files with 386 additions and 88 deletions
151
Headers/gnustep/base/fast.x
Normal file
151
Headers/gnustep/base/fast.x
Normal file
|
@ -0,0 +1,151 @@
|
|||
/* Performance enhancing utilities GNUStep
|
||||
Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
Date: October 1998
|
||||
|
||||
This file is part of the GNUstep Base 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 <config.h>
|
||||
#include <gnustep/base/preface.h>
|
||||
#include <objc/objc-api.h>
|
||||
|
||||
#ifndef INLINE
|
||||
#define INLINE inline
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file is all to do with improving performance by avoiding the
|
||||
* Objective-C messaging overhead in time-critical code.
|
||||
*
|
||||
* The motiviation behind it is to keep all the information needed to
|
||||
* do that in one place (using a single mechanism), so that optimization
|
||||
* attempts can be kept track of.
|
||||
*
|
||||
* The optimisations are of three sorts -
|
||||
*
|
||||
* 1. inline functions
|
||||
* There are many operations that can be speeded up by using inline
|
||||
* code to examine objects rather than sending messages to them to
|
||||
* ask them about themselves. Often, the objc runtime provides
|
||||
* functions to do this, but these sometimes perform unnecessary
|
||||
* checks. Here we attempt to provide some basics.
|
||||
*
|
||||
* 2. class comparison
|
||||
* It is often necessary to check the class of objects - instead of
|
||||
* using [+class] method, we can cache certain classes in a global
|
||||
* structure (The [NSObject +initialize] method does the caching)
|
||||
* and refer to the structure elements directly.
|
||||
*
|
||||
* 3. direct method despatch
|
||||
* A common techique is to obtain the method implementation for a
|
||||
* specific message sent to a particular class of object, and call
|
||||
* the implementation directly to avoid repeated lookup within the
|
||||
* objc runtime.
|
||||
* While there is no huge speed advantage to caching the method
|
||||
* implementations, it does make it easy to search the source for
|
||||
* code that is using this technique and referring to a cached
|
||||
* method implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Structure to cache class information.
|
||||
* By convention, the name of the structure element is the name of the
|
||||
* class with an underscore prepended.
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
* String classes
|
||||
*/
|
||||
Class _NSString;
|
||||
Class _NSGString;
|
||||
Class _NSGMutableString;
|
||||
Class _NSGCString;
|
||||
Class _NSGMutableCString;
|
||||
Class _NXConstantString;
|
||||
} fastCls;
|
||||
extern fastCls _fastCls; /* Populated by NSObject */
|
||||
|
||||
/*
|
||||
* Structure to cache method implementation information.
|
||||
* By convention, the name of the structure element consists of an
|
||||
* underscore followed by the name of the class, another underscore, and
|
||||
* the name of the method (with colons replaced by underscores).
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
* String implementations.
|
||||
*/
|
||||
unsigned (*_NSString_hash)();
|
||||
unsigned (*_NSGString_hash)();
|
||||
BOOL (*_NSGString_isEqual_)();
|
||||
BOOL (*_NSGCString_isEqual_)();
|
||||
} fastImp;
|
||||
extern fastImp _fastImp; /* Populated by NSObject */
|
||||
|
||||
/*
|
||||
* Fast access to class info - DON'T pass nil to these!
|
||||
*/
|
||||
|
||||
static INLINE BOOL
|
||||
fastIsInstance(id obj)
|
||||
{
|
||||
return CLS_ISCLASS(obj->class_pointer);
|
||||
}
|
||||
|
||||
static INLINE Class
|
||||
fastClass(NSObject* obj)
|
||||
{
|
||||
return ((id)obj)->class_pointer;
|
||||
}
|
||||
|
||||
static INLINE Class
|
||||
fastClassOfInstance(NSObject* obj)
|
||||
{
|
||||
if (fastIsInstance((id)obj))
|
||||
return fastClass(obj);
|
||||
return Nil;
|
||||
}
|
||||
|
||||
static INLINE Class
|
||||
fastSuper(Class cls)
|
||||
{
|
||||
return cls->super_class;
|
||||
}
|
||||
|
||||
static INLINE BOOL
|
||||
fastClassIsKindOfClass(Class c0, Class c1)
|
||||
{
|
||||
while (c0 != Nil) {
|
||||
if (c0 == c1)
|
||||
return YES;
|
||||
c0 = class_get_super_class(c0);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
static INLINE BOOL
|
||||
fastInstanceIsKindOfClass(NSObject *obj, Class c)
|
||||
{
|
||||
Class ic = fastClassOfInstance(obj);
|
||||
|
||||
if (ic == Nil)
|
||||
return NO;
|
||||
return fastClassIsKindOfClass(ic, c);
|
||||
}
|
||||
|
135
Source/FastMap.x
135
Source/FastMap.x
|
@ -26,6 +26,11 @@
|
|||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSZone.h>
|
||||
|
||||
/* To easily un-inline functions for debugging */
|
||||
#ifndef INLINE
|
||||
#define INLINE inline
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file should be INCLUDED in files wanting to use the FastMap
|
||||
* functions - these are all declared inline for maximum performance.
|
||||
|
@ -86,9 +91,6 @@
|
|||
#define FAST_MAP_EQUAL(X,Y) [(X).o isEqual: (Y).o]
|
||||
#endif
|
||||
|
||||
/* To easily un-inline functions for debugging */
|
||||
#define INLINE inline
|
||||
|
||||
typedef union {
|
||||
NSObject *o;
|
||||
long int i;
|
||||
|
@ -125,6 +127,9 @@ struct _FastMapTable {
|
|||
FastMapNode firstNode; /* List for enumerating. */
|
||||
size_t bucketCount; /* Number of buckets in map. */
|
||||
FastMapBucket buckets; /* Array of buckets. */
|
||||
FastMapNode freeNodes; /* List of unused nodes. */
|
||||
size_t chunkCount; /* Number of chunks in array. */
|
||||
FastMapNode *nodeChunks; /* Chunks of allocated memory. */
|
||||
};
|
||||
|
||||
struct _FastMapEnumerator {
|
||||
|
@ -245,49 +250,96 @@ FastMapRemangleBuckets(FastMapTable map,
|
|||
}
|
||||
}
|
||||
|
||||
static INLINE void
|
||||
FastMapMoreNodes(FastMapTable map)
|
||||
{
|
||||
FastMapNode *newArray;
|
||||
size_t arraySize = (map->chunkCount+1)*sizeof(FastMapNode);
|
||||
|
||||
newArray = (FastMapNode*)NSZoneMalloc(map->zone, arraySize);
|
||||
|
||||
if (newArray) {
|
||||
FastMapNode newNodes;
|
||||
size_t chunkCount;
|
||||
size_t chunkSize;
|
||||
|
||||
memcpy(newArray,map->nodeChunks,(map->chunkCount)*sizeof(FastMapNode));
|
||||
if (map->nodeChunks != 0)
|
||||
NSZoneFree(map->zone, map->nodeChunks);
|
||||
map->nodeChunks = newArray;
|
||||
|
||||
if (map->chunkCount == 0) {
|
||||
chunkCount = map->bucketCount > 1 ? map->bucketCount : 2;
|
||||
}
|
||||
else {
|
||||
chunkCount = ((map->nodeCount>>2)+1)<<1;
|
||||
}
|
||||
chunkSize = chunkCount * sizeof(FastMapNode_t);
|
||||
newNodes = (FastMapNode)NSZoneMalloc(map->zone, chunkSize);
|
||||
if (newNodes) {
|
||||
map->nodeChunks[map->chunkCount++] = newNodes;
|
||||
newNodes[--chunkCount].nextInMap = map->freeNodes;
|
||||
while (chunkCount--) {
|
||||
newNodes[chunkCount].nextInMap = &newNodes[chunkCount+1];
|
||||
}
|
||||
map->freeNodes = newNodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if FAST_MAP_HAS_VALUE
|
||||
static INLINE FastMapNode
|
||||
FastMapNewNode(FastMapTable map, FastMapItem key, FastMapItem value)
|
||||
{
|
||||
FastMapNode node;
|
||||
FastMapNode node = map->freeNodes;
|
||||
|
||||
node = (FastMapNode)NSZoneMalloc(map->zone, sizeof(FastMapNode_t));
|
||||
|
||||
if (node != 0) {
|
||||
node->key = key;
|
||||
node->value = value;
|
||||
node->nextInBucket = 0;
|
||||
node->nextInMap = 0;
|
||||
if (node == 0) {
|
||||
FastMapMoreNodes(map);
|
||||
node = map->freeNodes;
|
||||
if (node == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
map->freeNodes = node->nextInMap;
|
||||
node->key = key;
|
||||
node->value = value;
|
||||
node->nextInBucket = 0;
|
||||
node->nextInMap = 0;
|
||||
|
||||
return node;
|
||||
}
|
||||
#else
|
||||
static INLINE FastMapNode
|
||||
FastMapNewNode(FastMapTable map, FastMapItem key)
|
||||
{
|
||||
FastMapNode node;
|
||||
FastMapNode node = map->freeNodes;
|
||||
|
||||
node = (FastMapNode)NSZoneMalloc(map->zone, sizeof(FastMapNode_t));
|
||||
|
||||
if (node != 0) {
|
||||
node->key = key;
|
||||
node->nextInBucket = 0;
|
||||
node->nextInMap = 0;
|
||||
if (node = 0) {
|
||||
FastMapMoreNodes(map);
|
||||
node = map->freeNodes;
|
||||
if (node == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
map->freeNodes = node->nextInMap;
|
||||
node->key = key;
|
||||
node->nextInBucket = 0;
|
||||
node->nextInMap = 0;
|
||||
return node;
|
||||
}
|
||||
#endif
|
||||
|
||||
static INLINE void
|
||||
FastMapFreeNode(FastMapNode node)
|
||||
FastMapFreeNode(FastMapTable map, FastMapNode node)
|
||||
{
|
||||
if (node != 0) {
|
||||
FAST_MAP_RELEASE_KEY(node->key);
|
||||
FAST_MAP_RELEASE_KEY(node->key);
|
||||
#if FAST_MAP_HAS_VALUE
|
||||
FAST_MAP_RELEASE_VAL(node->value);
|
||||
FAST_MAP_RELEASE_VAL(node->value);
|
||||
#endif
|
||||
NSZoneFree(NSZoneFromPointer(node), node);
|
||||
}
|
||||
node->nextInMap = map->freeNodes;
|
||||
map->freeNodes = node;
|
||||
}
|
||||
|
||||
static INLINE FastMapNode
|
||||
|
@ -312,7 +364,7 @@ FastMapNodeForKey(FastMapTable map, FastMapItem key)
|
|||
return node;
|
||||
}
|
||||
|
||||
static INLINE size_t
|
||||
static INLINE void
|
||||
FastMapResize(FastMapTable map, size_t new_capacity)
|
||||
{
|
||||
FastMapBucket new_buckets;
|
||||
|
@ -352,12 +404,9 @@ FastMapResize(FastMapTable map, size_t new_capacity)
|
|||
map->buckets = new_buckets;
|
||||
map->bucketCount = size;
|
||||
}
|
||||
|
||||
/* Return the new capacity. */
|
||||
return map->bucketCount;
|
||||
}
|
||||
|
||||
static INLINE size_t
|
||||
static INLINE void
|
||||
FastMapRightSizeMap(FastMapTable map, size_t capacity)
|
||||
{
|
||||
/* FIXME: Now, this is a guess, based solely on my intuition. If anyone
|
||||
|
@ -366,10 +415,7 @@ FastMapRightSizeMap(FastMapTable map, size_t capacity)
|
|||
* L. Jones <Albin.L.Jones@Dartmouth.EDU>. */
|
||||
|
||||
if (3 * capacity >= 4 * map->bucketCount) {
|
||||
return FastMapResize(map, (3 * capacity)/4 + 1);
|
||||
}
|
||||
else {
|
||||
return map->bucketCount;
|
||||
FastMapResize(map, (3 * capacity)/4 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,7 +543,7 @@ FastMapRemoveKey(FastMapTable map, FastMapItem key)
|
|||
|
||||
if (node != 0) {
|
||||
FastMapRemoveNodeFromMap(map, bucket, node);
|
||||
FastMapFreeNode(node);
|
||||
FastMapFreeNode(map, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -513,17 +559,28 @@ FastMapEmptyMap(FastMapTable map)
|
|||
FastMapNode node = bucket->firstNode;
|
||||
|
||||
FastMapRemoveNodeFromBucket(bucket, node);
|
||||
FastMapFreeNode(node);
|
||||
FastMapFreeNode(map, node);
|
||||
}
|
||||
bucket++;
|
||||
}
|
||||
if (map->buckets != 0) {
|
||||
NSZoneFree(map->zone, map->buckets);
|
||||
map->buckets = 0;
|
||||
map->bucketCount = 0;
|
||||
}
|
||||
if (map->nodeChunks != 0) {
|
||||
for (i = 0; i < map->chunkCount; i++) {
|
||||
NSZoneFree(map->zone, map->nodeChunks[i]);
|
||||
}
|
||||
map->chunkCount = 0;
|
||||
NSZoneFree(map->zone, map->nodeChunks);
|
||||
map->nodeChunks = 0;
|
||||
}
|
||||
|
||||
map->firstNode = 0;
|
||||
map->nodeCount = 0;
|
||||
map->buckets = 0;
|
||||
map->bucketCount = 0;
|
||||
map->freeNodes = 0;
|
||||
map->zone = 0;
|
||||
}
|
||||
|
||||
static INLINE FastMapTable
|
||||
|
@ -534,7 +591,11 @@ FastMapInitWithZoneAndCapacity(FastMapTable map, NSZone *zone, size_t capacity)
|
|||
map->bucketCount = 0;
|
||||
map->firstNode = 0;
|
||||
map->buckets = 0;
|
||||
map->nodeChunks = 0;
|
||||
map->freeNodes = 0;
|
||||
map->chunkCount = 0;
|
||||
FastMapRightSizeMap(map, capacity);
|
||||
FastMapMoreNodes(map);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -33,25 +33,10 @@
|
|||
#include <gnustep/base/behavior.h>
|
||||
|
||||
#include <gnustep/base/Unicode.h>
|
||||
|
||||
static Class immutableClass;
|
||||
static Class mutableClass;
|
||||
static Class constantClass;
|
||||
#include <gnustep/base/fast.x>
|
||||
|
||||
@implementation NSGCString
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
static int done = 0;
|
||||
if (!done)
|
||||
{
|
||||
done = 1;
|
||||
immutableClass = [NSGCString class];
|
||||
mutableClass = [NSGMutableCString class];
|
||||
constantClass = [NXConstantString class];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_free_contents)
|
||||
|
@ -62,7 +47,7 @@ static Class constantClass;
|
|||
- (unsigned) hash
|
||||
{
|
||||
if (_hash == 0)
|
||||
if ((_hash = [super hash]) == 0)
|
||||
if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0)
|
||||
_hash = 0xffffffff;
|
||||
return _hash;
|
||||
}
|
||||
|
@ -274,18 +259,19 @@ static Class constantClass;
|
|||
Class c;
|
||||
if (anObject == self)
|
||||
return YES;
|
||||
c = [anObject class];
|
||||
c = fastClassOfInstance(anObject);
|
||||
|
||||
if (c == immutableClass || c == mutableClass || c == constantClass)
|
||||
if (c == _fastCls._NSGCString || c == _fastCls._NSGMutableCString || c == _fastCls._NXConstantString)
|
||||
{
|
||||
NSGCString *other = (NSGCString*)anObject;
|
||||
|
||||
if (_count != other->_count)
|
||||
return NO;
|
||||
if (_hash == 0)
|
||||
if ((_hash = [super hash]) == 0)
|
||||
if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0)
|
||||
_hash = 0xffffffff;
|
||||
if (other->_hash == 0) [other hash];
|
||||
if (other->_hash == 0)
|
||||
_fastImp._NSGString_hash(other, @selector(hash));
|
||||
if (_hash != other->_hash)
|
||||
return NO;
|
||||
if (memcmp(_contents_chars, other->_contents_chars, _count) != 0)
|
||||
|
@ -302,15 +288,18 @@ static Class constantClass;
|
|||
{
|
||||
Class c;
|
||||
|
||||
c = [aString class];
|
||||
if (c == immutableClass || c == mutableClass || c == constantClass)
|
||||
c = fastClassOfInstance(aString);
|
||||
if (c == _fastCls._NSGCString || c == _fastCls._NSGMutableCString || c == _fastCls._NXConstantString)
|
||||
{
|
||||
NSGCString *other = (NSGCString*)aString;
|
||||
|
||||
if (_count != other->_count)
|
||||
return NO;
|
||||
if (_hash == 0) [self hash];
|
||||
if (other->_hash == 0) [other hash];
|
||||
if (_hash == 0)
|
||||
if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0)
|
||||
_hash = 0xffffffff;
|
||||
if (other->_hash == 0)
|
||||
_fastImp._NSGString_hash(other, @selector(hash));
|
||||
if (_hash != other->_hash)
|
||||
return NO;
|
||||
if (memcmp(_contents_chars, other->_contents_chars, _count) != 0)
|
||||
|
|
|
@ -28,10 +28,72 @@
|
|||
#include <Foundation/NSString.h>
|
||||
#include <gnustep/base/Coding.h>
|
||||
|
||||
#include <gnustep/base/fast.x>
|
||||
|
||||
/*
|
||||
* Evil hack - this structure MUST correspond to the layout of all
|
||||
* instances of the string classes we know about!
|
||||
*/
|
||||
typedef struct {
|
||||
Class *isa;
|
||||
char *_contents_chars;
|
||||
int _count;
|
||||
BOOL _free_when_done;
|
||||
unsigned _hash;
|
||||
} *dictAccessToStringHack;
|
||||
|
||||
static INLINE unsigned
|
||||
myHash(NSObject *obj)
|
||||
{
|
||||
if (fastIsInstance(obj)) {
|
||||
Class c = fastClass(obj);
|
||||
|
||||
if (c == _fastCls._NXConstantString ||
|
||||
c == _fastCls._NSGCString ||
|
||||
c == _fastCls._NSGMutableCString ||
|
||||
c == _fastCls._NSGString ||
|
||||
c == _fastCls._NSGMutableString) {
|
||||
|
||||
if (((dictAccessToStringHack)obj)->_hash != 0) {
|
||||
return ((dictAccessToStringHack)obj)->_hash;
|
||||
}
|
||||
return _fastImp._NSGString_hash(obj, @selector(hash));
|
||||
}
|
||||
}
|
||||
return [obj hash];
|
||||
}
|
||||
|
||||
static INLINE BOOL
|
||||
myEqual(NSObject *self, NSObject *other)
|
||||
{
|
||||
if (self == other) {
|
||||
return YES;
|
||||
}
|
||||
if (fastIsInstance(self)) {
|
||||
Class c = fastClass(self);
|
||||
|
||||
if (c == _fastCls._NXConstantString ||
|
||||
c == _fastCls._NSGCString ||
|
||||
c == _fastCls._NSGMutableCString) {
|
||||
return _fastImp._NSGCString_isEqual_(self,
|
||||
@selector(isEqual:), other);
|
||||
}
|
||||
if (c == _fastCls._NSGString ||
|
||||
c == _fastCls._NSGMutableString) {
|
||||
return _fastImp._NSGString_isEqual_(self,
|
||||
@selector(isEqual:), other);
|
||||
}
|
||||
}
|
||||
return [self isEqual: other];
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'Fastmap' stuff provides an inline implementation of a mapping
|
||||
* table - for maximum performance.
|
||||
*/
|
||||
#define FAST_MAP_HASH(X) myHash(X.o)
|
||||
#define FAST_MAP_EQUAL(X,Y) myEqual(X.o,Y.o)
|
||||
|
||||
#include "FastMap.x"
|
||||
|
||||
@class NSDictionaryNonCore;
|
||||
|
|
|
@ -38,25 +38,12 @@
|
|||
#include <gnustep/base/NSGSequence.h>
|
||||
/* memcpy(), strlen(), strcmp() are gcc builtin's */
|
||||
|
||||
#include <gnustep/base/fast.x>
|
||||
#include <gnustep/base/Unicode.h>
|
||||
|
||||
|
||||
@implementation NSGString
|
||||
|
||||
static Class immutableClass;
|
||||
static Class mutableClass;
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
static int done = 0;
|
||||
if (!done)
|
||||
{
|
||||
done = 1;
|
||||
immutableClass = [NSGString class];
|
||||
mutableClass = [NSGMutableString class];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (_free_contents)
|
||||
|
@ -70,7 +57,7 @@ static Class mutableClass;
|
|||
- (unsigned) hash
|
||||
{
|
||||
if (_hash == 0)
|
||||
if ((_hash = [super hash]) == 0)
|
||||
if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0)
|
||||
_hash = 0xffffffff;
|
||||
return _hash;
|
||||
}
|
||||
|
@ -80,13 +67,15 @@ static Class mutableClass;
|
|||
Class c;
|
||||
if (anObject == self)
|
||||
return YES;
|
||||
c = [anObject class];
|
||||
if (c == immutableClass || c == mutableClass)
|
||||
c = fastClassOfInstance(anObject);
|
||||
if (c == _fastCls._NSGString || c == _fastCls._NSGMutableString)
|
||||
{
|
||||
NSGString *other = (NSGString*)anObject;
|
||||
|
||||
if (_hash == 0) [self hash];
|
||||
if (other->_hash == 0) [other hash];
|
||||
if (_hash == 0)
|
||||
_fastImp._NSGString_hash(self, @selector(hash));
|
||||
if (other->_hash == 0)
|
||||
_fastImp._NSGString_hash(self, @selector(hash));
|
||||
if (_hash != other->_hash)
|
||||
return NO;
|
||||
return [self isEqualToString: other];
|
||||
|
|
|
@ -37,6 +37,11 @@
|
|||
#include <Foundation/NSZone.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <gnustep/base/fast.x>
|
||||
|
||||
fastCls _fastCls; /* Structure to cache classes. */
|
||||
fastImp _fastImp; /* Structure to cache methods. */
|
||||
|
||||
|
||||
/*
|
||||
* Reference count and memory management
|
||||
|
@ -309,6 +314,26 @@ static BOOL double_release_check_enabled = NO;
|
|||
retain_counts_gate = objc_mutex_allocate ();
|
||||
#endif
|
||||
autorelease_class = [NSAutoreleasePool class];
|
||||
/*
|
||||
* Cache some classes for quick access later.
|
||||
*/
|
||||
_fastCls._NSString = [NSString class];
|
||||
_fastCls._NSGString = [NSGString class];
|
||||
_fastCls._NSGMutableString = [NSGMutableString class];
|
||||
_fastCls._NSGCString = [NSGCString class];
|
||||
_fastCls._NSGMutableCString = [NSGMutableCString class];
|
||||
_fastCls._NXConstantString = [NXConstantString class];
|
||||
/*
|
||||
* Cache some method implementations for quick access later.
|
||||
*/
|
||||
_fastImp._NSString_hash = (unsigned (*)())[_fastCls._NSString
|
||||
instanceMethodForSelector: @selector(hash)];
|
||||
_fastImp._NSGString_hash = (unsigned (*)())[_fastCls._NSGString
|
||||
instanceMethodForSelector: @selector(hash)];
|
||||
_fastImp._NSGString_isEqual_ = (BOOL (*)())[_fastCls._NSGString
|
||||
instanceMethodForSelector: @selector(isEqual:)];
|
||||
_fastImp._NSGCString_isEqual_ = (BOOL (*)())[_fastCls._NSGCString
|
||||
instanceMethodForSelector: @selector(isEqual:)];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -269,14 +269,14 @@ handle_printf_atsign (FILE *stream,
|
|||
|
||||
+ (NSString*) stringWithCString: (const char*) byteString
|
||||
{
|
||||
return [[[self alloc] initWithCString:byteString]
|
||||
return [[[NSString_c_concrete_class alloc] initWithCString:byteString]
|
||||
autorelease];
|
||||
}
|
||||
|
||||
+ (NSString*) stringWithCString: (const char*)byteString
|
||||
length: (unsigned int)length
|
||||
{
|
||||
return [[[self alloc]
|
||||
return [[[NSString_c_concrete_class alloc]
|
||||
initWithCString:byteString length:length]
|
||||
autorelease];
|
||||
}
|
||||
|
@ -1552,15 +1552,34 @@ else
|
|||
} while(notdone);
|
||||
|
||||
p = source;
|
||||
|
||||
while (*p && char_count++ < NSHashStringLength)
|
||||
{
|
||||
#if 1
|
||||
ret = (ret << 5) + ret + *p++;
|
||||
#else
|
||||
#if 1
|
||||
ret = (ret << 4) + *p++;
|
||||
ctr = ret & 0xf0000000L;
|
||||
if (ctr != 0)
|
||||
ret ^= ctr ^ (ctr >> 24);
|
||||
#else
|
||||
ret ^= *p++ << ctr;
|
||||
ctr = (ctr + 4) % 20;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* The hash caching in our concrete strin classes uses zero to denote
|
||||
* an empty cache value, so we must not return a hash of zero.
|
||||
*/
|
||||
if (ret == 0)
|
||||
ret = 0xffffffff;
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
return 0xfffffffe; /* Hash for an empty string. */
|
||||
}
|
||||
|
||||
// Getting a Shared Prefix
|
||||
|
@ -2660,15 +2679,17 @@ else
|
|||
|
||||
+ (NSString*) stringWithCString: (const char*)byteString
|
||||
{
|
||||
return [self stringWithCString:byteString length:strlen(byteString)];
|
||||
return [[[NSMutableString_c_concrete_class alloc]
|
||||
initWithCString:byteString]
|
||||
autorelease];
|
||||
}
|
||||
|
||||
+ (NSString*) stringWithCString: (const char*)byteString
|
||||
length: (unsigned int)length
|
||||
{
|
||||
return [[[self alloc]
|
||||
initWithCString:byteString length:length]
|
||||
autorelease];
|
||||
return [[[NSMutableString_c_concrete_class alloc]
|
||||
initWithCString:byteString length:length]
|
||||
autorelease];
|
||||
}
|
||||
|
||||
/* xxx Change this when we have non-CString classes */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue