Optimisation of attributed string handling - hoping this might help

a little with NSText performance - but probably not noticable


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@6510 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2000-04-25 15:42:57 +00:00
parent 0ba0eb1ca8
commit fc807728e6
2 changed files with 159 additions and 81 deletions

View file

@ -1,3 +1,8 @@
2000-04-23 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSAttributedString.m: Optimised - cache method implementations
wherever possible in order to avoid objc runtime overheads.
2000-04-23 Richard Frith-Macdonald <rfm@gnu.org> 2000-04-23 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSAttributedString.m: Corrected code of * Source/NSAttributedString.m: Corrected code of

View file

@ -55,6 +55,24 @@
#include <Foundation/NSPortCoder.h> #include <Foundation/NSPortCoder.h>
#include <Foundation/NSRange.h> #include <Foundation/NSRange.h>
static SEL eqSel = @selector(isEqual:);
static SEL setSel = @selector(setAttributes:range:);
static SEL getSel = @selector(attributesAtIndex:effectiveRange:);
static SEL addDictSel = @selector(addEntriesFromDictionary:);
static SEL setDictSel = @selector(setObject:forKey:);
static SEL relDictSel = @selector(release);
static SEL remDictSel = @selector(removeObjectForKey:);
@class NSGMutableDictionary;
static Class dictionaryClass = 0;
static SEL allocDictSel = @selector(allocWithZone:);
static SEL initDictSel = @selector(initWithDictionary:);
static IMP allocDictImp;
static IMP initDictImp;
static IMP addDictImp;
static IMP setDictImp;
static IMP relDictImp;
static IMP remDictImp;
@interface GSMutableAttributedStringTracker : NSMutableString @interface GSMutableAttributedStringTracker : NSMutableString
{ {
@ -102,6 +120,13 @@ static Class NSMutableAttributedString_concrete_class;
= [NSMutableAttributedString class]; = [NSMutableAttributedString class];
NSMutableAttributedString_concrete_class NSMutableAttributedString_concrete_class
= [NSGMutableAttributedString class]; = [NSGMutableAttributedString class];
dictionaryClass = [NSGMutableDictionary class];
allocDictImp = [dictionaryClass methodForSelector: allocDictSel];
initDictImp = [dictionaryClass instanceMethodForSelector: initDictSel];
addDictImp = [dictionaryClass instanceMethodForSelector: addDictSel];
setDictImp = [dictionaryClass instanceMethodForSelector: setDictSel];
remDictImp = [dictionaryClass instanceMethodForSelector: remDictSel];
relDictImp = [dictionaryClass instanceMethodForSelector: relDictSel];
} }
} }
@ -223,21 +248,22 @@ static Class NSMutableAttributedString_concrete_class;
{ {
NSDictionary *attrDictionary, *tmpDictionary; NSDictionary *attrDictionary, *tmpDictionary;
NSRange tmpRange; NSRange tmpRange;
IMP getImp;
if (rangeLimit.location < 0 || NSMaxRange(rangeLimit) > [self length]) if (rangeLimit.location < 0 || NSMaxRange(rangeLimit) > [self length])
{ {
[NSException raise: NSRangeException [NSException raise: NSRangeException
format: @"RangeError in method -attributesAtIndex:longestEffectiveRange:inRange: in class NSAttributedString"]; format: @"RangeError in method -attributesAtIndex:longestEffectiveRange:inRange: in class NSAttributedString"];
} }
attrDictionary = [self attributesAtIndex: index effectiveRange: aRange]; getImp = [self methodForSelector: getSel];
attrDictionary = (*getImp)(self, getSel, index, aRange);
if (aRange == 0) if (aRange == 0)
return attrDictionary; return attrDictionary;
while (aRange->location > rangeLimit.location) while (aRange->location > rangeLimit.location)
{ {
//Check extend range backwards //Check extend range backwards
tmpDictionary = [self attributesAtIndex: aRange->location-1 tmpDictionary = (*getImp)(self, getSel, aRange->location-1, &tmpRange);
effectiveRange: &tmpRange];
if ([tmpDictionary isEqualToDictionary: attrDictionary]) if ([tmpDictionary isEqualToDictionary: attrDictionary])
{ {
aRange->length = NSMaxRange(*aRange) - tmpRange.location; aRange->length = NSMaxRange(*aRange) - tmpRange.location;
@ -251,8 +277,7 @@ static Class NSMutableAttributedString_concrete_class;
while (NSMaxRange(*aRange) < NSMaxRange(rangeLimit)) while (NSMaxRange(*aRange) < NSMaxRange(rangeLimit))
{ {
//Check extend range forwards //Check extend range forwards
tmpDictionary = [self attributesAtIndex: NSMaxRange(*aRange) tmpDictionary = (*getImp)(self, getSel, NSMaxRange(*aRange), &tmpRange);
effectiveRange: &tmpRange];
if ([tmpDictionary isEqualToDictionary: attrDictionary]) if ([tmpDictionary isEqualToDictionary: attrDictionary])
{ {
aRange->length = NSMaxRange(tmpRange) - aRange->location; aRange->length = NSMaxRange(tmpRange) - aRange->location;
@ -301,34 +326,37 @@ static Class NSMutableAttributedString_concrete_class;
id tmpAttrValue; id tmpAttrValue;
NSRange tmpRange; NSRange tmpRange;
BOOL (*eImp)(id,SEL,id); BOOL (*eImp)(id,SEL,id);
IMP getImp;
if (rangeLimit.location < 0 || NSMaxRange(rangeLimit) > [self length]) if (rangeLimit.location < 0 || NSMaxRange(rangeLimit) > [self length])
{ {
[NSException raise: NSRangeException [NSException raise: NSRangeException
format: @"RangeError in method -attribute:atIndex:longestEffectiveRange:inRange: in class NSAttributedString"]; format: @"RangeError in method -attribute:atIndex:longestEffectiveRange:inRange: in class NSAttributedString"];
} }
if (attributeName == nil) if (attributeName == nil)
return nil; return nil;
attrValue = [self attribute: attributeName attrValue = [self attribute: attributeName
atIndex: index atIndex: index
effectiveRange: aRange]; effectiveRange: aRange];
if (aRange == 0) if (aRange == 0)
return attrValue; return attrValue;
/* /*
* If attrValue == nil then eImp will be zero * If attrValue == nil then eImp will be zero
*/ */
eImp = (BOOL(*)(id,SEL,id))[attrValue methodForSelector: @selector(isEqual:)]; eImp = (BOOL(*)(id,SEL,id))[attrValue methodForSelector: eqSel];
getImp = [self methodForSelector: getSel];
while (aRange->location > rangeLimit.location) while (aRange->location > rangeLimit.location)
{ {
//Check extend range backwards //Check extend range backwards
tmpDictionary = [self attributesAtIndex: aRange->location-1 tmpDictionary = (*getImp)(self, getSel, aRange->location-1, &tmpRange);
effectiveRange: &tmpRange];
tmpAttrValue = [tmpDictionary objectForKey: attributeName]; tmpAttrValue = [tmpDictionary objectForKey: attributeName];
if (tmpAttrValue == attrValue if (tmpAttrValue == attrValue
|| (eImp != 0 && (*eImp)(attrValue, @selector(isEqual), tmpAttrValue))) || (eImp != 0 && (*eImp)(attrValue, eqSel, tmpAttrValue)))
{ {
aRange->length = NSMaxRange(*aRange) - tmpRange.location; aRange->length = NSMaxRange(*aRange) - tmpRange.location;
aRange->location = tmpRange.location; aRange->location = tmpRange.location;
@ -341,11 +369,10 @@ static Class NSMutableAttributedString_concrete_class;
while (NSMaxRange(*aRange) < NSMaxRange(rangeLimit)) while (NSMaxRange(*aRange) < NSMaxRange(rangeLimit))
{ {
//Check extend range forwards //Check extend range forwards
tmpDictionary = [self attributesAtIndex: NSMaxRange(*aRange) tmpDictionary = (*getImp)(self, getSel, NSMaxRange(*aRange), &tmpRange);
effectiveRange: &tmpRange];
tmpAttrValue = [tmpDictionary objectForKey: attributeName]; tmpAttrValue = [tmpDictionary objectForKey: attributeName];
if (tmpAttrValue == attrValue if (tmpAttrValue == attrValue
|| (eImp != 0 && (*eImp)(attrValue, @selector(isEqual), tmpAttrValue))) || (eImp != 0 && (*eImp)(attrValue, eqSel, tmpAttrValue)))
{ {
aRange->length = NSMaxRange(tmpRange) - aRange->location; aRange->length = NSMaxRange(tmpRange) - aRange->location;
} }
@ -412,7 +439,7 @@ static Class NSMutableAttributedString_concrete_class;
{ {
if (anObject == self) if (anObject == self)
return YES; return YES;
if ([anObject isKindOf: [NSAttributedString class]]) if ([anObject isKindOfClass: NSAttributedString_abstract_class])
return [self isEqualToAttributedString: anObject]; return [self isEqualToAttributedString: anObject];
return NO; return NO;
} }
@ -435,16 +462,17 @@ static Class NSMutableAttributedString_concrete_class;
range = NSIntersectionRange(range, aRange); range = NSIntersectionRange(range, aRange);
if (NSEqualRanges(range, aRange) == YES) if (NSEqualRanges(range, aRange) == YES)
{ {
newAttrString = [[NSAttributedString alloc] initWithString: newSubstring newAttrString = [NSAttributedString_concrete_class alloc];
attributes: attrs]; newAttrString = [newAttrString initWithString: newSubstring
attributes: attrs];
} }
else else
{ {
NSMutableAttributedString *m; NSMutableAttributedString *m;
NSRange rangeToSet = range; NSRange rangeToSet = range;
m = [[NSMutableAttributedString alloc] initWithString: newSubstring m = [NSMutableAttributedString_concrete_class alloc];
attributes: nil]; m = [m initWithString: newSubstring attributes: nil];
rangeToSet.location = 0; rangeToSet.location = 0;
[m setAttributes: attrs range: rangeToSet]; [m setAttributes: attrs range: rangeToSet];
while (NSMaxRange(range) < NSMaxRange(aRange)) while (NSMaxRange(range) < NSMaxRange(aRange))
@ -499,30 +527,40 @@ static Class NSMutableAttributedString_concrete_class;
NSDictionary *attrDict; NSDictionary *attrDict;
NSMutableDictionary *newDict; NSMutableDictionary *newDict;
unsigned int tmpLength; unsigned int tmpLength;
IMP getImp;
tmpLength = [self length]; tmpLength = [self length];
GS_RANGE_CHECK(aRange, tmpLength); GS_RANGE_CHECK(aRange, tmpLength);
attrDict = [self attributesAtIndex: aRange.location getImp = [self methodForSelector: getSel];
effectiveRange: &effectiveRange]; attrDict = (*getImp)(self, getSel, aRange.location, &effectiveRange);
while (effectiveRange.location < NSMaxRange(aRange)) if (effectiveRange.location < NSMaxRange(aRange))
{ {
effectiveRange = NSIntersectionRange(aRange, effectiveRange); IMP setImp;
newDict = [[NSMutableDictionary alloc] initWithDictionary: attrDict]; setImp = [self methodForSelector: setSel];
IF_NO_GC(AUTORELEASE(newDict));
[newDict setObject: value forKey: name]; while (effectiveRange.location < NSMaxRange(aRange))
[self setAttributes: newDict range: effectiveRange];
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
{ {
effectiveRange.location = NSMaxRange(aRange);//This stops the loop... effectiveRange = NSIntersectionRange(aRange, effectiveRange);
}
else if (NSMaxRange(effectiveRange) < tmpLength) newDict = (*allocDictImp)(dictionaryClass, allocDictSel,
{ NSDefaultMallocZone());
attrDict = [self attributesAtIndex: NSMaxRange(effectiveRange) newDict = (*initDictImp)(newDict, initDictSel, attrDict);
effectiveRange: &effectiveRange]; (*setDictImp)(newDict, setDictSel, value, name);
(*setImp)(self, setSel, newDict, effectiveRange);
IF_NO_GC((*relDictImp)(newDict, relDictSel));
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
{
effectiveRange.location = NSMaxRange(aRange);// stop the loop...
}
else if (NSMaxRange(effectiveRange) < tmpLength)
{
attrDict = (*getImp)(self, getSel, NSMaxRange(effectiveRange),
&effectiveRange);
}
} }
} }
} }
@ -533,6 +571,7 @@ static Class NSMutableAttributedString_concrete_class;
NSDictionary *attrDict; NSDictionary *attrDict;
NSMutableDictionary *newDict; NSMutableDictionary *newDict;
unsigned int tmpLength; unsigned int tmpLength;
IMP getImp;
if (!attributes) if (!attributes)
{ {
@ -548,26 +587,35 @@ static Class NSMutableAttributedString_concrete_class;
@"in class NSMutableAttributedString"]; @"in class NSMutableAttributedString"];
} }
attrDict = [self attributesAtIndex: aRange.location getImp = [self methodForSelector: getSel];
effectiveRange: &effectiveRange]; attrDict = (*getImp)(self, getSel, aRange.location, &effectiveRange);
while (effectiveRange.location < NSMaxRange(aRange)) if (effectiveRange.location < NSMaxRange(aRange))
{ {
effectiveRange = NSIntersectionRange(aRange,effectiveRange); IMP setImp;
newDict = [[NSMutableDictionary alloc] initWithDictionary: attrDict]; setImp = [self methodForSelector: setSel];
IF_NO_GC(AUTORELEASE(newDict));
[newDict addEntriesFromDictionary: attributes]; while (effectiveRange.location < NSMaxRange(aRange))
[self setAttributes: newDict range: effectiveRange];
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
{ {
effectiveRange.location = NSMaxRange(aRange);//This stops the loop... effectiveRange = NSIntersectionRange(aRange,effectiveRange);
}
else if (NSMaxRange(effectiveRange) < tmpLength) newDict = (*allocDictImp)(dictionaryClass, allocDictSel,
{ NSDefaultMallocZone());
attrDict = [self attributesAtIndex: NSMaxRange(effectiveRange) newDict = (*initDictImp)(newDict, initDictSel, attrDict);
effectiveRange: &effectiveRange]; (*addDictImp)(newDict, addDictSel, attributes);
(*setImp)(self, setSel, newDict, effectiveRange);
IF_NO_GC((*relDictImp)(newDict, relDictSel));
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
{
effectiveRange.location = NSMaxRange(aRange);// stop the loop...
}
else if (NSMaxRange(effectiveRange) < tmpLength)
{
attrDict = (*getImp)(self, getSel, NSMaxRange(effectiveRange),
&effectiveRange);
}
} }
} }
} }
@ -578,30 +626,40 @@ static Class NSMutableAttributedString_concrete_class;
NSDictionary *attrDict; NSDictionary *attrDict;
NSMutableDictionary *newDict; NSMutableDictionary *newDict;
unsigned int tmpLength; unsigned int tmpLength;
IMP getImp;
tmpLength = [self length]; tmpLength = [self length];
GS_RANGE_CHECK(aRange, tmpLength); GS_RANGE_CHECK(aRange, tmpLength);
attrDict = [self attributesAtIndex: aRange.location getImp = [self methodForSelector: getSel];
effectiveRange: &effectiveRange]; attrDict = (*getImp)(self, getSel, aRange.location, &effectiveRange);
while (effectiveRange.location < NSMaxRange(aRange)) if (effectiveRange.location < NSMaxRange(aRange))
{ {
effectiveRange = NSIntersectionRange(aRange,effectiveRange); IMP setImp;
newDict = [[NSMutableDictionary alloc] initWithDictionary: attrDict]; setImp = [self methodForSelector: setSel];
IF_NO_GC(AUTORELEASE(newDict));
[newDict removeObjectForKey: name]; while (effectiveRange.location < NSMaxRange(aRange))
[self setAttributes: newDict range: effectiveRange];
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
{ {
effectiveRange.location = NSMaxRange(aRange);//This stops the loop... effectiveRange = NSIntersectionRange(aRange,effectiveRange);
}
else if (NSMaxRange(effectiveRange) < tmpLength) newDict = (*allocDictImp)(dictionaryClass, allocDictSel,
{ NSDefaultMallocZone());
attrDict = [self attributesAtIndex: NSMaxRange(effectiveRange) newDict = (*initDictImp)(newDict, initDictSel, attrDict);
effectiveRange: &effectiveRange]; (*remDictImp)(newDict, remDictSel, name);
(*setImp)(self, setSel, newDict, effectiveRange);
IF_NO_GC((*relDictImp)(newDict, relDictSel));
if (NSMaxRange(effectiveRange) >= NSMaxRange(aRange))
{
effectiveRange.location = NSMaxRange(aRange);// stop the loop...
}
else if (NSMaxRange(effectiveRange) < tmpLength)
{
attrDict = (*getImp)(self, getSel, NSMaxRange(effectiveRange),
&effectiveRange);
}
} }
} }
} }
@ -623,25 +681,40 @@ static Class NSMutableAttributedString_concrete_class;
- (void) replaceCharactersInRange: (NSRange)aRange - (void) replaceCharactersInRange: (NSRange)aRange
withAttributedString: (NSAttributedString*)attributedString withAttributedString: (NSAttributedString*)attributedString
{ {
NSRange effectiveRange;
NSRange clipRange;
NSRange ownRange;
NSDictionary *attrDict; NSDictionary *attrDict;
NSString *tmpStr; NSString *tmpStr;
unsigned loc; unsigned max;
if (attributedString == nil)
{
[self replaceCharactersInRange: aRange withString: nil];
return;
}
tmpStr = [attributedString string]; tmpStr = [attributedString string];
[self replaceCharactersInRange: aRange withString: tmpStr]; [self replaceCharactersInRange: aRange withString: tmpStr];
max = [tmpStr length];
effectiveRange = NSMakeRange(0,0);
clipRange = NSMakeRange(0,[tmpStr length]); if (max > 0)
while ((loc = NSMaxRange(effectiveRange)) < NSMaxRange(clipRange))
{ {
attrDict = [attributedString attributesAtIndex: loc unsigned loc = 0;
effectiveRange: &effectiveRange]; NSRange effectiveRange = NSMakeRange(0, loc);
ownRange = NSIntersectionRange(clipRange, effectiveRange); NSRange clipRange = NSMakeRange(0, max);
ownRange.location += aRange.location; IMP getImp;
[self setAttributes: attrDict range: ownRange]; IMP setImp;
getImp = [attributedString methodForSelector: getSel];
setImp = [self methodForSelector: setSel];
while (loc < max)
{
NSRange ownRange;
attrDict = (*getImp)(attributedString, getSel, loc, &effectiveRange);
ownRange = NSIntersectionRange(clipRange, effectiveRange);
ownRange.location += aRange.location;
(*setImp)(self, setSel, attrDict, ownRange);
loc = NSMaxRange(effectiveRange);
}
} }
} }