mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-20 20:26:42 +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
26e47289b1
commit
39b8ff1baf
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/NSObject.h>
|
||||||
#include <Foundation/NSZone.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
|
* This file should be INCLUDED in files wanting to use the FastMap
|
||||||
* functions - these are all declared inline for maximum performance.
|
* functions - these are all declared inline for maximum performance.
|
||||||
|
@ -86,9 +91,6 @@
|
||||||
#define FAST_MAP_EQUAL(X,Y) [(X).o isEqual: (Y).o]
|
#define FAST_MAP_EQUAL(X,Y) [(X).o isEqual: (Y).o]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* To easily un-inline functions for debugging */
|
|
||||||
#define INLINE inline
|
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
NSObject *o;
|
NSObject *o;
|
||||||
long int i;
|
long int i;
|
||||||
|
@ -125,6 +127,9 @@ struct _FastMapTable {
|
||||||
FastMapNode firstNode; /* List for enumerating. */
|
FastMapNode firstNode; /* List for enumerating. */
|
||||||
size_t bucketCount; /* Number of buckets in map. */
|
size_t bucketCount; /* Number of buckets in map. */
|
||||||
FastMapBucket buckets; /* Array of buckets. */
|
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 {
|
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
|
#if FAST_MAP_HAS_VALUE
|
||||||
static INLINE FastMapNode
|
static INLINE FastMapNode
|
||||||
FastMapNewNode(FastMapTable map, FastMapItem key, FastMapItem value)
|
FastMapNewNode(FastMapTable map, FastMapItem key, FastMapItem value)
|
||||||
{
|
{
|
||||||
FastMapNode node;
|
FastMapNode node = map->freeNodes;
|
||||||
|
|
||||||
node = (FastMapNode)NSZoneMalloc(map->zone, sizeof(FastMapNode_t));
|
if (node == 0) {
|
||||||
|
FastMapMoreNodes(map);
|
||||||
if (node != 0) {
|
node = map->freeNodes;
|
||||||
node->key = key;
|
if (node == 0) {
|
||||||
node->value = value;
|
return 0;
|
||||||
node->nextInBucket = 0;
|
}
|
||||||
node->nextInMap = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map->freeNodes = node->nextInMap;
|
||||||
|
node->key = key;
|
||||||
|
node->value = value;
|
||||||
|
node->nextInBucket = 0;
|
||||||
|
node->nextInMap = 0;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static INLINE FastMapNode
|
static INLINE FastMapNode
|
||||||
FastMapNewNode(FastMapTable map, FastMapItem key)
|
FastMapNewNode(FastMapTable map, FastMapItem key)
|
||||||
{
|
{
|
||||||
FastMapNode node;
|
FastMapNode node = map->freeNodes;
|
||||||
|
|
||||||
node = (FastMapNode)NSZoneMalloc(map->zone, sizeof(FastMapNode_t));
|
if (node = 0) {
|
||||||
|
FastMapMoreNodes(map);
|
||||||
if (node != 0) {
|
node = map->freeNodes;
|
||||||
node->key = key;
|
if (node == 0) {
|
||||||
node->nextInBucket = 0;
|
return 0;
|
||||||
node->nextInMap = 0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map->freeNodes = node->nextInMap;
|
||||||
|
node->key = key;
|
||||||
|
node->nextInBucket = 0;
|
||||||
|
node->nextInMap = 0;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static INLINE void
|
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
|
#if FAST_MAP_HAS_VALUE
|
||||||
FAST_MAP_RELEASE_VAL(node->value);
|
FAST_MAP_RELEASE_VAL(node->value);
|
||||||
#endif
|
#endif
|
||||||
NSZoneFree(NSZoneFromPointer(node), node);
|
node->nextInMap = map->freeNodes;
|
||||||
}
|
map->freeNodes = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE FastMapNode
|
static INLINE FastMapNode
|
||||||
|
@ -312,7 +364,7 @@ FastMapNodeForKey(FastMapTable map, FastMapItem key)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE size_t
|
static INLINE void
|
||||||
FastMapResize(FastMapTable map, size_t new_capacity)
|
FastMapResize(FastMapTable map, size_t new_capacity)
|
||||||
{
|
{
|
||||||
FastMapBucket new_buckets;
|
FastMapBucket new_buckets;
|
||||||
|
@ -352,12 +404,9 @@ FastMapResize(FastMapTable map, size_t new_capacity)
|
||||||
map->buckets = new_buckets;
|
map->buckets = new_buckets;
|
||||||
map->bucketCount = size;
|
map->bucketCount = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the new capacity. */
|
|
||||||
return map->bucketCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE size_t
|
static INLINE void
|
||||||
FastMapRightSizeMap(FastMapTable map, size_t capacity)
|
FastMapRightSizeMap(FastMapTable map, size_t capacity)
|
||||||
{
|
{
|
||||||
/* FIXME: Now, this is a guess, based solely on my intuition. If anyone
|
/* 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>. */
|
* L. Jones <Albin.L.Jones@Dartmouth.EDU>. */
|
||||||
|
|
||||||
if (3 * capacity >= 4 * map->bucketCount) {
|
if (3 * capacity >= 4 * map->bucketCount) {
|
||||||
return FastMapResize(map, (3 * capacity)/4 + 1);
|
FastMapResize(map, (3 * capacity)/4 + 1);
|
||||||
}
|
|
||||||
else {
|
|
||||||
return map->bucketCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +543,7 @@ FastMapRemoveKey(FastMapTable map, FastMapItem key)
|
||||||
|
|
||||||
if (node != 0) {
|
if (node != 0) {
|
||||||
FastMapRemoveNodeFromMap(map, bucket, node);
|
FastMapRemoveNodeFromMap(map, bucket, node);
|
||||||
FastMapFreeNode(node);
|
FastMapFreeNode(map, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -513,17 +559,28 @@ FastMapEmptyMap(FastMapTable map)
|
||||||
FastMapNode node = bucket->firstNode;
|
FastMapNode node = bucket->firstNode;
|
||||||
|
|
||||||
FastMapRemoveNodeFromBucket(bucket, node);
|
FastMapRemoveNodeFromBucket(bucket, node);
|
||||||
FastMapFreeNode(node);
|
FastMapFreeNode(map, node);
|
||||||
}
|
}
|
||||||
bucket++;
|
bucket++;
|
||||||
}
|
}
|
||||||
if (map->buckets != 0) {
|
if (map->buckets != 0) {
|
||||||
NSZoneFree(map->zone, map->buckets);
|
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->firstNode = 0;
|
||||||
map->nodeCount = 0;
|
map->nodeCount = 0;
|
||||||
map->buckets = 0;
|
map->freeNodes = 0;
|
||||||
map->bucketCount = 0;
|
map->zone = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static INLINE FastMapTable
|
static INLINE FastMapTable
|
||||||
|
@ -534,7 +591,11 @@ FastMapInitWithZoneAndCapacity(FastMapTable map, NSZone *zone, size_t capacity)
|
||||||
map->bucketCount = 0;
|
map->bucketCount = 0;
|
||||||
map->firstNode = 0;
|
map->firstNode = 0;
|
||||||
map->buckets = 0;
|
map->buckets = 0;
|
||||||
|
map->nodeChunks = 0;
|
||||||
|
map->freeNodes = 0;
|
||||||
|
map->chunkCount = 0;
|
||||||
FastMapRightSizeMap(map, capacity);
|
FastMapRightSizeMap(map, capacity);
|
||||||
|
FastMapMoreNodes(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,25 +33,10 @@
|
||||||
#include <gnustep/base/behavior.h>
|
#include <gnustep/base/behavior.h>
|
||||||
|
|
||||||
#include <gnustep/base/Unicode.h>
|
#include <gnustep/base/Unicode.h>
|
||||||
|
#include <gnustep/base/fast.x>
|
||||||
static Class immutableClass;
|
|
||||||
static Class mutableClass;
|
|
||||||
static Class constantClass;
|
|
||||||
|
|
||||||
@implementation NSGCString
|
@implementation NSGCString
|
||||||
|
|
||||||
+ (void) initialize
|
|
||||||
{
|
|
||||||
static int done = 0;
|
|
||||||
if (!done)
|
|
||||||
{
|
|
||||||
done = 1;
|
|
||||||
immutableClass = [NSGCString class];
|
|
||||||
mutableClass = [NSGMutableCString class];
|
|
||||||
constantClass = [NXConstantString class];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
if (_free_contents)
|
if (_free_contents)
|
||||||
|
@ -62,7 +47,7 @@ static Class constantClass;
|
||||||
- (unsigned) hash
|
- (unsigned) hash
|
||||||
{
|
{
|
||||||
if (_hash == 0)
|
if (_hash == 0)
|
||||||
if ((_hash = [super hash]) == 0)
|
if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0)
|
||||||
_hash = 0xffffffff;
|
_hash = 0xffffffff;
|
||||||
return _hash;
|
return _hash;
|
||||||
}
|
}
|
||||||
|
@ -274,18 +259,19 @@ static Class constantClass;
|
||||||
Class c;
|
Class c;
|
||||||
if (anObject == self)
|
if (anObject == self)
|
||||||
return YES;
|
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;
|
NSGCString *other = (NSGCString*)anObject;
|
||||||
|
|
||||||
if (_count != other->_count)
|
if (_count != other->_count)
|
||||||
return NO;
|
return NO;
|
||||||
if (_hash == 0)
|
if (_hash == 0)
|
||||||
if ((_hash = [super hash]) == 0)
|
if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0)
|
||||||
_hash = 0xffffffff;
|
_hash = 0xffffffff;
|
||||||
if (other->_hash == 0) [other hash];
|
if (other->_hash == 0)
|
||||||
|
_fastImp._NSGString_hash(other, @selector(hash));
|
||||||
if (_hash != other->_hash)
|
if (_hash != other->_hash)
|
||||||
return NO;
|
return NO;
|
||||||
if (memcmp(_contents_chars, other->_contents_chars, _count) != 0)
|
if (memcmp(_contents_chars, other->_contents_chars, _count) != 0)
|
||||||
|
@ -302,15 +288,18 @@ static Class constantClass;
|
||||||
{
|
{
|
||||||
Class c;
|
Class c;
|
||||||
|
|
||||||
c = [aString class];
|
c = fastClassOfInstance(aString);
|
||||||
if (c == immutableClass || c == mutableClass || c == constantClass)
|
if (c == _fastCls._NSGCString || c == _fastCls._NSGMutableCString || c == _fastCls._NXConstantString)
|
||||||
{
|
{
|
||||||
NSGCString *other = (NSGCString*)aString;
|
NSGCString *other = (NSGCString*)aString;
|
||||||
|
|
||||||
if (_count != other->_count)
|
if (_count != other->_count)
|
||||||
return NO;
|
return NO;
|
||||||
if (_hash == 0) [self hash];
|
if (_hash == 0)
|
||||||
if (other->_hash == 0) [other hash];
|
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)
|
if (_hash != other->_hash)
|
||||||
return NO;
|
return NO;
|
||||||
if (memcmp(_contents_chars, other->_contents_chars, _count) != 0)
|
if (memcmp(_contents_chars, other->_contents_chars, _count) != 0)
|
||||||
|
|
|
@ -28,10 +28,72 @@
|
||||||
#include <Foundation/NSString.h>
|
#include <Foundation/NSString.h>
|
||||||
#include <gnustep/base/Coding.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
|
* The 'Fastmap' stuff provides an inline implementation of a mapping
|
||||||
* table - for maximum performance.
|
* 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"
|
#include "FastMap.x"
|
||||||
|
|
||||||
@class NSDictionaryNonCore;
|
@class NSDictionaryNonCore;
|
||||||
|
|
|
@ -38,25 +38,12 @@
|
||||||
#include <gnustep/base/NSGSequence.h>
|
#include <gnustep/base/NSGSequence.h>
|
||||||
/* memcpy(), strlen(), strcmp() are gcc builtin's */
|
/* memcpy(), strlen(), strcmp() are gcc builtin's */
|
||||||
|
|
||||||
|
#include <gnustep/base/fast.x>
|
||||||
#include <gnustep/base/Unicode.h>
|
#include <gnustep/base/Unicode.h>
|
||||||
|
|
||||||
|
|
||||||
@implementation NSGString
|
@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
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
if (_free_contents)
|
if (_free_contents)
|
||||||
|
@ -70,7 +57,7 @@ static Class mutableClass;
|
||||||
- (unsigned) hash
|
- (unsigned) hash
|
||||||
{
|
{
|
||||||
if (_hash == 0)
|
if (_hash == 0)
|
||||||
if ((_hash = [super hash]) == 0)
|
if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0)
|
||||||
_hash = 0xffffffff;
|
_hash = 0xffffffff;
|
||||||
return _hash;
|
return _hash;
|
||||||
}
|
}
|
||||||
|
@ -80,13 +67,15 @@ static Class mutableClass;
|
||||||
Class c;
|
Class c;
|
||||||
if (anObject == self)
|
if (anObject == self)
|
||||||
return YES;
|
return YES;
|
||||||
c = [anObject class];
|
c = fastClassOfInstance(anObject);
|
||||||
if (c == immutableClass || c == mutableClass)
|
if (c == _fastCls._NSGString || c == _fastCls._NSGMutableString)
|
||||||
{
|
{
|
||||||
NSGString *other = (NSGString*)anObject;
|
NSGString *other = (NSGString*)anObject;
|
||||||
|
|
||||||
if (_hash == 0) [self hash];
|
if (_hash == 0)
|
||||||
if (other->_hash == 0) [other hash];
|
_fastImp._NSGString_hash(self, @selector(hash));
|
||||||
|
if (other->_hash == 0)
|
||||||
|
_fastImp._NSGString_hash(self, @selector(hash));
|
||||||
if (_hash != other->_hash)
|
if (_hash != other->_hash)
|
||||||
return NO;
|
return NO;
|
||||||
return [self isEqualToString: other];
|
return [self isEqualToString: other];
|
||||||
|
|
|
@ -37,6 +37,11 @@
|
||||||
#include <Foundation/NSZone.h>
|
#include <Foundation/NSZone.h>
|
||||||
#include <limits.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
|
* Reference count and memory management
|
||||||
|
@ -309,6 +314,26 @@ static BOOL double_release_check_enabled = NO;
|
||||||
retain_counts_gate = objc_mutex_allocate ();
|
retain_counts_gate = objc_mutex_allocate ();
|
||||||
#endif
|
#endif
|
||||||
autorelease_class = [NSAutoreleasePool class];
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,14 +269,14 @@ handle_printf_atsign (FILE *stream,
|
||||||
|
|
||||||
+ (NSString*) stringWithCString: (const char*) byteString
|
+ (NSString*) stringWithCString: (const char*) byteString
|
||||||
{
|
{
|
||||||
return [[[self alloc] initWithCString:byteString]
|
return [[[NSString_c_concrete_class alloc] initWithCString:byteString]
|
||||||
autorelease];
|
autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSString*) stringWithCString: (const char*)byteString
|
+ (NSString*) stringWithCString: (const char*)byteString
|
||||||
length: (unsigned int)length
|
length: (unsigned int)length
|
||||||
{
|
{
|
||||||
return [[[self alloc]
|
return [[[NSString_c_concrete_class alloc]
|
||||||
initWithCString:byteString length:length]
|
initWithCString:byteString length:length]
|
||||||
autorelease];
|
autorelease];
|
||||||
}
|
}
|
||||||
|
@ -1552,15 +1552,34 @@ else
|
||||||
} while(notdone);
|
} while(notdone);
|
||||||
|
|
||||||
p = source;
|
p = source;
|
||||||
|
|
||||||
while (*p && char_count++ < NSHashStringLength)
|
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;
|
ret ^= *p++ << ctr;
|
||||||
ctr = (ctr + 4) % 20;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return 0;
|
return 0xfffffffe; /* Hash for an empty string. */
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting a Shared Prefix
|
// Getting a Shared Prefix
|
||||||
|
@ -2660,15 +2679,17 @@ else
|
||||||
|
|
||||||
+ (NSString*) stringWithCString: (const char*)byteString
|
+ (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
|
+ (NSString*) stringWithCString: (const char*)byteString
|
||||||
length: (unsigned int)length
|
length: (unsigned int)length
|
||||||
{
|
{
|
||||||
return [[[self alloc]
|
return [[[NSMutableString_c_concrete_class alloc]
|
||||||
initWithCString:byteString length:length]
|
initWithCString:byteString length:length]
|
||||||
autorelease];
|
autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* xxx Change this when we have non-CString classes */
|
/* xxx Change this when we have non-CString classes */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue