diff --git a/Headers/gnustep/base/NSGCString.h b/Headers/gnustep/base/NSGCString.h index 9ea2bcf4a..b1f1fe0be 100644 --- a/Headers/gnustep/base/NSGCString.h +++ b/Headers/gnustep/base/NSGCString.h @@ -27,8 +27,12 @@ #include #include -/* NSGCString and NSGMutableCString must have the same initial ivar layout - because of class_add_behavior() in NSGMutableCString's +initialize. */ +/* + * NSGCString and NSGMutableCString must have the same initial ivar layout + * because of class_add_behavior() in NSGMutableCString's +initialize + * and because the various string classes (and NSGDictionary) examine and + * set each others _hash ivar directly for performance reasons! + */ @interface NSGCString : NSString { diff --git a/Headers/gnustep/base/fast.x b/Headers/gnustep/base/fast.x index c12eb534b..3ceb10aa8 100644 --- a/Headers/gnustep/base/fast.x +++ b/Headers/gnustep/base/fast.x @@ -92,7 +92,7 @@ typedef struct { * String implementations. */ unsigned (*_NSString_hash)(); - unsigned (*_NSGString_hash)(); + BOOL (*_NSString_isEqualToString_)(); BOOL (*_NSGString_isEqual_)(); BOOL (*_NSGCString_isEqual_)(); } fastImp; diff --git a/Source/NSGCString.m b/Source/NSGCString.m index b16268307..998cce45d 100644 --- a/Source/NSGCString.m +++ b/Source/NSGCString.m @@ -47,8 +47,7 @@ - (unsigned) hash { if (_hash == 0) - if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0) - _hash = 0xffffffff; + _hash = _fastImp._NSString_hash(self, @selector(hash)); return _hash; } @@ -116,7 +115,6 @@ - initWithCoder: aCoder { - [super initWithCoder:aCoder]; [aCoder decodeValueOfObjCType:@encode(char*) at:&_contents_chars withName:NULL]; _count = strlen(_contents_chars); @@ -270,20 +268,22 @@ if (_count != other->_count) return NO; if (_hash == 0) - if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0) - _hash = 0xffffffff; + _hash = _fastImp._NSString_hash(self, @selector(hash)); if (other->_hash == 0) - _fastImp._NSGString_hash(other, @selector(hash)); + other->_hash = _fastImp._NSString_hash(other, @selector(hash)); if (_hash != other->_hash) return NO; if (memcmp(_contents_chars, other->_contents_chars, _count) != 0) return NO; return YES; } - else if ([c isKindOfClass: [NSString class]]) - return [super isEqualToString: (NSString*)anObject]; + else if (c == nil) + return NO; + else if (fastClassIsKindOfClass(c, _fastCls._NSString)) + return _fastImp._NSString_isEqualToString_(self, + @selector(isEqualToString:), anObject); else - return [super isEqual: anObject]; + return NO; } - (BOOL) isEqualToString: (NSString*)aString @@ -302,18 +302,22 @@ if (_count != other->_count) return NO; if (_hash == 0) - if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0) - _hash = 0xffffffff; + _hash = _fastImp._NSString_hash(self, @selector(hash)); if (other->_hash == 0) - _fastImp._NSGString_hash(other, @selector(hash)); + other->_hash = _fastImp._NSString_hash(other, @selector(hash)); if (_hash != other->_hash) return NO; if (memcmp(_contents_chars, other->_contents_chars, _count) != 0) return NO; return YES; } + else if (c == nil) + return NO; + else if (fastClassIsKindOfClass(c, _fastCls._NSString)) + return _fastImp._NSString_isEqualToString_(self, + @selector(isEqualToString:), aString); else - return [super isEqualToString: aString]; + return NO; } diff --git a/Source/NSGDictionary.m b/Source/NSGDictionary.m index 664dbb896..f6ad06af2 100644 --- a/Source/NSGDictionary.m +++ b/Source/NSGDictionary.m @@ -55,10 +55,11 @@ myHash(NSObject *obj) c == _fastCls._NSGString || c == _fastCls._NSGMutableString) { - if (((dictAccessToStringHack)obj)->_hash != 0) { - return ((dictAccessToStringHack)obj)->_hash; + if (((dictAccessToStringHack)obj)->_hash == 0) { + ((dictAccessToStringHack)obj)->_hash = + _fastImp._NSString_hash(obj, @selector(hash)); } - return _fastImp._NSGString_hash(obj, @selector(hash)); + return ((dictAccessToStringHack)obj)->_hash; } } return [obj hash]; diff --git a/Source/NSGString.m b/Source/NSGString.m index 878402e71..b50d35f64 100644 --- a/Source/NSGString.m +++ b/Source/NSGString.m @@ -57,8 +57,7 @@ - (unsigned) hash { if (_hash == 0) - if ((_hash = _fastImp._NSString_hash(self, @selector(hash))) == 0) - _hash = 0xffffffff; + _hash = _fastImp._NSString_hash(self, @selector(hash)); return _hash; } @@ -70,20 +69,28 @@ if (anObject == nil) return NO; c = fastClassOfInstance(anObject); - if (c == _fastCls._NSGString || c == _fastCls._NSGMutableString) + if (c == _fastCls._NSGString || c == _fastCls._NSGMutableString || + c == _fastCls._NSGCString || c == _fastCls._NSGMutableCString || + c == _fastCls._NXConstantString) { NSGString *other = (NSGString*)anObject; if (_hash == 0) - _fastImp._NSGString_hash(self, @selector(hash)); + _hash = _fastImp._NSString_hash(self, @selector(hash)); if (other->_hash == 0) - _fastImp._NSGString_hash(other, @selector(hash)); + other->_hash = _fastImp._NSString_hash(other, @selector(hash)); if (_hash != other->_hash) return NO; - return [self isEqualToString: other]; + return _fastImp._NSString_isEqualToString_(self, + @selector(isEqualToString:), other); } + else if (c == nil) + return NO; + else if (fastClassIsKindOfClass(c, _fastCls._NSString)) + return _fastImp._NSString_isEqualToString_(self, + @selector(isEqualToString:), anObject); else - return [super isEqual: anObject]; + return NO; } // Initializing Newly Allocated Strings @@ -231,7 +238,6 @@ - (void) encodeWithCoder: aCoder { - [super encodeWithCoder:aCoder]; // *** added this [aCoder encodeValueOfObjCType:@encode(int) at:&_count withName:@"Concrete String count"]; [aCoder encodeArrayOfObjCType:@encode(unichar) @@ -242,7 +248,6 @@ - initWithCoder: aCoder { - [super initWithCoder:aCoder]; [aCoder decodeValueOfObjCType:@encode(int) at:&_count withName:NULL]; OBJC_MALLOC(_contents_chars, unichar, _count+1); diff --git a/Source/NSObject.m b/Source/NSObject.m index f456400e9..afb6a5ca4 100644 --- a/Source/NSObject.m +++ b/Source/NSObject.m @@ -47,19 +47,22 @@ void _fastBuildCache() /* * 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._NSString_isEqualToString_ = (BOOL (*)())[_fastCls._NSString + instanceMethodForSelector: @selector(isEqualToString:)]; _fastImp._NSGString_isEqual_ = (BOOL (*)())[_fastCls._NSGString instanceMethodForSelector: @selector(isEqual:)]; _fastImp._NSGCString_isEqual_ = (BOOL (*)())[_fastCls._NSGCString diff --git a/Source/NSString.m b/Source/NSString.m index 7d9f93b85..93035b6b8 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -66,6 +66,9 @@ #include #include +#include + + // Uncomment when implemented static NSStringEncoding _availableEncodings[] = { NSASCIIStringEncoding, @@ -1406,11 +1409,19 @@ else - (BOOL) isEqual: (id)anObject { - if (anObject == self) - return YES; - if ([anObject isKindOfClass:[NSString class]] == YES) - return [self isEqualToString:anObject]; - return NO; + if (anObject == self) { + return YES; + } + if (anObject != nil) { + Class c = fastClassOfInstance(anObject); + + if (c != nil) { + if (fastClassIsKindOfClass(c, _fastCls._NSString)) { + return [self isEqualToString: anObject]; + } + } + } + return NO; } - (BOOL) isEqualToString: (NSString*)aString @@ -1572,7 +1583,7 @@ else /* * 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. + * an empty cache value, so we MUST NOT return a hash of zero. */ if (ret == 0) ret = 0xffffffff; @@ -2640,12 +2651,13 @@ else - (void) encodeWithCoder: anEncoder { - [super encodeWithCoder:anEncoder]; + [self subclassResponsibility:_cmd]; } - initWithCoder: aDecoder { - return [super initWithCoder:aDecoder]; + [self subclassResponsibility:_cmd]; + return self; } @end