Optimised NSScanner

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@4882 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1999-09-13 05:24:42 +00:00
parent 93f37dfa37
commit 92a427d24f
2 changed files with 215 additions and 144 deletions

View file

@ -1,3 +1,8 @@
Mon Sep 13 6:45:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
Miscellaneous minor bugfixes plyus,
* Source/NSScanner.m: optimised (well, mostly).
Sun Sep 12 20:22:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk> Sun Sep 12 20:22:00 1999 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* Source/NSDictionary.m: optimise by avoiding objc method lookup * Source/NSDictionary.m: optimise by avoiding objc method lookup

View file

@ -22,8 +22,11 @@
*/ */
#include <config.h> #include <config.h>
#include <base/fast.x>
#include <Foundation/NSScanner.h> #include <Foundation/NSScanner.h>
#include <Foundation/NSException.h> #include <Foundation/NSException.h>
#include <Foundation/NSGString.h>
#include <Foundation/NSUserDefaults.h>
#include <float.h> #include <float.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
@ -31,6 +34,30 @@
@implementation NSScanner @implementation NSScanner
static Class NSString_class;
static Class NSGString_class;
static NSCharacterSet *defaultSkipSet;
static SEL memSel = @selector(characterIsMember:);
/*
* Hack for direct access to internals of an NSGString object.
*/
typedef struct {
@defs(NSGString)
} *stringAccess;
#define charAtIndex(I) ((stringAccess)string)->_contents_chars[I]
+ (void) initialize
{
if (self == [NSScanner class])
{
defaultSkipSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
RETAIN(defaultSkipSet);
NSString_class = [NSString class];
NSGString_class = [NSGString class];
}
}
/* /*
* Create and return a scanner that scans aString. * Create and return a scanner that scans aString.
*/ */
@ -39,10 +66,13 @@
return AUTORELEASE([[self alloc] initWithString: aString]); return AUTORELEASE([[self alloc] initWithString: aString]);
} }
+ (id) localizedScannerWithString: (NSString*)locale + (id) localizedScannerWithString: (NSString*)aString
{ {
[self notImplemented: _cmd]; NSScanner *scanner = [self scannerWithString: aString];
return Nil; NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
scanner->locale = RETAIN([defs dictionaryRepresentation]);
return scanner;
} }
/* /*
@ -52,9 +82,21 @@
- (id) initWithString: (NSString *)aString - (id) initWithString: (NSString *)aString
{ {
[super init]; [super init];
string = [aString copyWithZone: [self zone]]; /*
* Ensure that we have an NSGString so we can access its internals directly.
*/
if (fastClass(aString) == NSGString_class)
string = RETAIN(aString);
else if ([aString isKindOfClass: NSString_class])
string = [[NSGString_class alloc] initWithString: aString];
else
{
[self dealloc];
[NSException raise: NSInvalidArgumentException
format: @"Scanner initialised with something not a string"];
}
len = [string length]; len = [string length];
charactersToBeSkipped = RETAIN([NSCharacterSet whitespaceAndNewlineCharacterSet]); charactersToBeSkipped = RETAIN(defaultSkipSet);
return self; return self;
} }
@ -64,7 +106,7 @@
- (void) dealloc - (void) dealloc
{ {
RELEASE(string); RELEASE(string);
RELEASE(locale); TEST_RELEASE(locale);
RELEASE(charactersToBeSkipped); RELEASE(charactersToBeSkipped);
[super dealloc]; [super dealloc];
} }
@ -74,16 +116,19 @@
* For internal use only. * For internal use only.
*/ */
- (BOOL) _scanCharactersFromSet: (NSCharacterSet *)set - (BOOL) _scanCharactersFromSet: (NSCharacterSet *)set
intoString: (NSString **)value; intoString: (NSString **)value;
{ {
unsigned int start; unsigned int start;
BOOL (*memImp)(NSCharacterSet*, SEL, unichar);
if (scanLocation >= len) if (scanLocation >= len)
return NO; return NO;
memImp = (BOOL (*)(NSCharacterSet*, SEL, unichar))
[set methodForSelector: memSel];
start = scanLocation; start = scanLocation;
while (scanLocation < len) while (scanLocation < len)
{ {
if (![set characterIsMember: [string characterAtIndex: scanLocation]]) if ((*memImp)(set, memSel, charAtIndex(scanLocation)) == NO)
break; break;
scanLocation++; scanLocation++;
} }
@ -153,21 +198,24 @@
BOOL got_digits = NO; BOOL got_digits = NO;
/* Check for sign */ /* Check for sign */
switch ([string characterAtIndex: scanLocation]) if (scanLocation < len)
{ {
case '+': switch (charAtIndex(scanLocation))
scanLocation++; {
break; case '+':
case '-': scanLocation++;
negative = YES; break;
scanLocation++; case '-':
break; negative = YES;
scanLocation++;
break;
}
} }
/* Process digits */ /* Process digits */
while (scanLocation < len) while (scanLocation < len)
{ {
unichar digit = [string characterAtIndex: scanLocation]; unichar digit = charAtIndex(scanLocation);
if ((digit < '0') || (digit > '9')) if ((digit < '0') || (digit > '9'))
break; break;
if (!overflow) { if (!overflow) {
@ -185,7 +233,8 @@
return NO; return NO;
if (value) if (value)
{ {
if (overflow || (num > (negative ? (unsigned int)INT_MIN : (unsigned int)INT_MAX))) if (overflow
|| (num > (negative ? (unsigned int)INT_MIN : (unsigned int)INT_MAX)))
*value = negative ? INT_MIN: INT_MAX; *value = negative ? INT_MIN: INT_MAX;
else if (negative) else if (negative)
*value = -num; *value = -num;
@ -212,7 +261,9 @@
* Scan an unsigned int of the given radix into value. * Scan an unsigned int of the given radix into value.
* Internal version used by scanRadixUnsignedInt: and scanHexInt: . * Internal version used by scanRadixUnsignedInt: and scanHexInt: .
*/ */
- (BOOL) scanUnsignedInt_: (unsigned int *)value radix: (int)radix gotDigits: (BOOL)gotDigits - (BOOL) scanUnsignedInt_: (unsigned int *)value
radix: (int)radix
gotDigits: (BOOL)gotDigits
{ {
unsigned int num = 0; unsigned int num = 0;
unsigned int numLimit, digitLimit, digitValue; unsigned int numLimit, digitLimit, digitValue;
@ -226,44 +277,45 @@
/* Process digits */ /* Process digits */
while (scanLocation < len) while (scanLocation < len)
{ {
unichar digit = [string characterAtIndex: scanLocation]; unichar digit = charAtIndex(scanLocation);
switch (digit) switch (digit)
{ {
case '0': digitValue = 0; break; case '0': digitValue = 0; break;
case '1': digitValue = 1; break; case '1': digitValue = 1; break;
case '2': digitValue = 2; break; case '2': digitValue = 2; break;
case '3': digitValue = 3; break; case '3': digitValue = 3; break;
case '4': digitValue = 4; break; case '4': digitValue = 4; break;
case '5': digitValue = 5; break; case '5': digitValue = 5; break;
case '6': digitValue = 6; break; case '6': digitValue = 6; break;
case '7': digitValue = 7; break; case '7': digitValue = 7; break;
case '8': digitValue = 8; break; case '8': digitValue = 8; break;
case '9': digitValue = 9; break; case '9': digitValue = 9; break;
case 'a': digitValue = 0xA; break; case 'a': digitValue = 0xA; break;
case 'b': digitValue = 0xB; break; case 'b': digitValue = 0xB; break;
case 'c': digitValue = 0xC; break; case 'c': digitValue = 0xC; break;
case 'd': digitValue = 0xD; break; case 'd': digitValue = 0xD; break;
case 'e': digitValue = 0xE; break; case 'e': digitValue = 0xE; break;
case 'f': digitValue = 0xF; break; case 'f': digitValue = 0xF; break;
case 'A': digitValue = 0xA; break; case 'A': digitValue = 0xA; break;
case 'B': digitValue = 0xB; break; case 'B': digitValue = 0xB; break;
case 'C': digitValue = 0xC; break; case 'C': digitValue = 0xC; break;
case 'D': digitValue = 0xD; break; case 'D': digitValue = 0xD; break;
case 'E': digitValue = 0xE; break; case 'E': digitValue = 0xE; break;
case 'F': digitValue = 0xF; break; case 'F': digitValue = 0xF; break;
default: default:
digitValue = radix; digitValue = radix;
break; break;
} }
if (digitValue >= radix) if (digitValue >= radix)
break; break;
if (!overflow) if (!overflow)
{ {
if ((num > numLimit) || ((num == numLimit) && (digitValue > digitLimit))) if ((num > numLimit)
overflow = YES; || ((num == numLimit) && (digitValue > digitLimit)))
else overflow = YES;
num = num * radix + digitValue; else
} num = num * radix + digitValue;
}
scanLocation++; scanLocation++;
gotDigits = YES; gotDigits = YES;
} }
@ -302,23 +354,23 @@
/* Check radix */ /* Check radix */
radix = 10; radix = 10;
if ((scanLocation < len) && ([string characterAtIndex: scanLocation] == '0')) if ((scanLocation < len) && (charAtIndex(scanLocation) == '0'))
{ {
radix = 8; radix = 8;
scanLocation++; scanLocation++;
gotDigits = YES; gotDigits = YES;
if (scanLocation < len) if (scanLocation < len)
{
switch ([string characterAtIndex: scanLocation])
{ {
case 'x': switch (charAtIndex(scanLocation))
case 'X': {
scanLocation++; case 'x':
radix = 16; case 'X':
gotDigits = NO; scanLocation++;
break; radix = 16;
gotDigits = NO;
break;
}
} }
}
} }
if ( [self scanUnsignedInt_: value radix: radix gotDigits: gotDigits]) if ( [self scanUnsignedInt_: value radix: radix gotDigits: gotDigits])
return YES; return YES;
@ -367,21 +419,24 @@
} }
/* Check for sign */ /* Check for sign */
switch ([string characterAtIndex: scanLocation]) if (scanLocation < len)
{ {
case '+': switch (charAtIndex(scanLocation))
scanLocation++; {
break; case '+':
case '-': scanLocation++;
negative = YES; break;
scanLocation++; case '-':
break; negative = YES;
scanLocation++;
break;
}
} }
/* Process digits */ /* Process digits */
while (scanLocation < len) while (scanLocation < len)
{ {
unichar digit = [string characterAtIndex: scanLocation]; unichar digit = charAtIndex(scanLocation);
if ((digit < '0') || (digit > '9')) if ((digit < '0') || (digit > '9'))
break; break;
if (!overflow) { if (!overflow) {
@ -431,14 +486,14 @@
*/ */
- (BOOL) scanDouble: (double *)value - (BOOL) scanDouble: (double *)value
{ {
unichar decimal; unichar decimal = '.';
unichar c = 0; unichar c = 0;
double num = 0.0; double num = 0.0;
long int exponent = 0; long int exponent = 0;
BOOL negative = NO; BOOL negative = NO;
BOOL got_dot = NO; BOOL got_dot = NO;
BOOL got_digit = NO; BOOL got_digit = NO;
unsigned int saveScanLocation = scanLocation; unsigned int saveScanLocation = scanLocation;
/* Skip whitespace */ /* Skip whitespace */
if (![self _skipToNextField]) if (![self _skipToNextField])
@ -448,28 +503,36 @@
} }
/* /*
* FIXME: Should get decimal point character from locale. * Get decimal point character from locale if necessary.
* The key is NSDecimalSeparator.
* The problem is that I can't find anything in GNUSTEP about locales.
*/ */
decimal = '.'; if (locale != nil)
{
NSString *pointString;
pointString = [locale objectForKey: NSDecimalSeparator];
if ([pointString length] > 0)
decimal = [pointString characterAtIndex: 0];
}
/* Check for sign */ /* Check for sign */
switch ([string characterAtIndex: scanLocation]) if (scanLocation < len)
{ {
case '+': switch (charAtIndex(scanLocation))
scanLocation++; {
break; case '+':
case '-': scanLocation++;
negative = YES; break;
scanLocation++; case '-':
break; negative = YES;
scanLocation++;
break;
}
} }
/* Process number */ /* Process number */
while (scanLocation < len) while (scanLocation < len)
{ {
c = [string characterAtIndex: scanLocation]; c = charAtIndex(scanLocation);
if ((c >= '0') && (c <= '9')) if ((c >= '0') && (c <= '9'))
{ {
/* Ensure that the number being accumulated will not overflow. */ /* Ensure that the number being accumulated will not overflow. */
@ -499,53 +562,53 @@
} }
scanLocation++; scanLocation++;
} }
if (!got_digit) if (!got_digit)
{ {
scanLocation = saveScanLocation; scanLocation = saveScanLocation;
return NO; return NO;
} }
/* Check for trailing exponent */ /* Check for trailing exponent */
if ((scanLocation < len) && ((c == 'e') || (c == 'E'))) if ((scanLocation < len) && ((c == 'e') || (c == 'E')))
{ {
int expval; int expval;
scanLocation++; scanLocation++;
if ([self _scanInt: &expval]) if ([self _scanInt: &expval])
{
/* Check for exponent overflow */
if (num)
{ {
/* Check for exponent overflow */ if ((exponent > 0) && (expval > (LONG_MAX - exponent)))
if (num) exponent = LONG_MAX;
{ else if ((exponent < 0) && (expval < (LONG_MIN - exponent)))
if ((exponent > 0) && (expval > (LONG_MAX - exponent))) exponent = LONG_MIN;
exponent = LONG_MAX; else
else if ((exponent < 0) && (expval < (LONG_MIN - exponent))) exponent += expval;
exponent = LONG_MIN;
else
exponent += expval;
}
} }
else }
{ else
{
#ifdef _ACCEPT_BAD_EXPONENTS_ #ifdef _ACCEPT_BAD_EXPONENTS_
/* Numbers like 1.23eFOO are accepted (as 1.23). */ /* Numbers like 1.23eFOO are accepted (as 1.23). */
scanLocation = expScanLocation; scanLocation = expScanLocation;
#else #else
/* Numbers like 1.23eFOO are rejected. */ /* Numbers like 1.23eFOO are rejected. */
scanLocation = saveScanLocation; scanLocation = saveScanLocation;
return NO; return NO;
#endif #endif
} }
} }
if (value) if (value)
{ {
if (num && exponent) if (num && exponent)
num *= pow(10.0, (double) exponent); num *= pow(10.0, (double) exponent);
if (negative) if (negative)
*value = -num; *value = -num;
else else
*value = num; *value = num;
} }
return YES; return YES;
} }
/* /*
@ -577,7 +640,7 @@
* containing the scanned characters is returned by reference in value. * containing the scanned characters is returned by reference in value.
*/ */
- (BOOL) scanCharactersFromSet: (NSCharacterSet *)aSet - (BOOL) scanCharactersFromSet: (NSCharacterSet *)aSet
intoString: (NSString **)value; intoString: (NSString **)value;
{ {
unsigned int saveScanLocation = scanLocation; unsigned int saveScanLocation = scanLocation;
@ -598,15 +661,18 @@
- (BOOL) scanUpToCharactersFromSet: (NSCharacterSet *)set - (BOOL) scanUpToCharactersFromSet: (NSCharacterSet *)set
intoString: (NSString **)value; intoString: (NSString **)value;
{ {
unsigned int saveScanLocation = scanLocation; unsigned int saveScanLocation = scanLocation;
unsigned int start; unsigned int start;
BOOL (*memImp)(NSCharacterSet*, SEL, unichar);
if (![self _skipToNextField]) if (![self _skipToNextField])
return NO; return NO;
start = scanLocation; start = scanLocation;
memImp = (BOOL (*)(NSCharacterSet*, SEL, unichar))
[set methodForSelector: memSel];
while (scanLocation < len) while (scanLocation < len)
{ {
if ([set characterIsMember: [string characterAtIndex: scanLocation]]) if ((*memImp)(set, memSel, charAtIndex(scanLocation)) == YES)
break; break;
scanLocation++; scanLocation++;
} }
@ -644,8 +710,8 @@
if (range.location + range.length > len) if (range.location + range.length > len)
return NO; return NO;
range = [string rangeOfString: aString range = [string rangeOfString: aString
options: caseSensitive ? 0 : NSCaseInsensitiveSearch options: caseSensitive ? 0 : NSCaseInsensitiveSearch
range: range]; range: range];
if (range.length == 0) if (range.length == 0)
{ {
scanLocation = saveScanLocation; scanLocation = saveScanLocation;
@ -675,8 +741,8 @@
range.location = scanLocation; range.location = scanLocation;
range.length = len - scanLocation; range.length = len - scanLocation;
found = [string rangeOfString: aString found = [string rangeOfString: aString
options: caseSensitive ? 0 : NSCaseInsensitiveSearch options: caseSensitive ? 0 : NSCaseInsensitiveSearch
range: range]; range: range];
if (found.length) if (found.length)
range.length = found.location - scanLocation; range.length = found.location - scanLocation;
if (range.length == 0) if (range.length == 0)
@ -768,7 +834,7 @@
*/ */
- (void) setLocale: (NSDictionary *)localeDictionary - (void) setLocale: (NSDictionary *)localeDictionary
{ {
locale = RETAIN(localeDictionary); ASSIGN(locale, localeDictionary);
} }
/* /*