mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
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:
parent
ca36a2f5ed
commit
422d4f25a7
2 changed files with 215 additions and 144 deletions
|
@ -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>
|
||||
|
||||
* Source/NSDictionary.m: optimise by avoiding objc method lookup
|
||||
|
|
|
@ -22,8 +22,11 @@
|
|||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <base/fast.x>
|
||||
#include <Foundation/NSScanner.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSGString.h>
|
||||
#include <Foundation/NSUserDefaults.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
@ -31,6 +34,30 @@
|
|||
|
||||
@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.
|
||||
*/
|
||||
|
@ -39,10 +66,13 @@
|
|||
return AUTORELEASE([[self alloc] initWithString: aString]);
|
||||
}
|
||||
|
||||
+ (id) localizedScannerWithString: (NSString*)locale
|
||||
+ (id) localizedScannerWithString: (NSString*)aString
|
||||
{
|
||||
[self notImplemented: _cmd];
|
||||
return Nil;
|
||||
NSScanner *scanner = [self scannerWithString: aString];
|
||||
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
scanner->locale = RETAIN([defs dictionaryRepresentation]);
|
||||
return scanner;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -52,9 +82,21 @@
|
|||
- (id) initWithString: (NSString *)aString
|
||||
{
|
||||
[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];
|
||||
charactersToBeSkipped = RETAIN([NSCharacterSet whitespaceAndNewlineCharacterSet]);
|
||||
charactersToBeSkipped = RETAIN(defaultSkipSet);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -64,7 +106,7 @@
|
|||
- (void) dealloc
|
||||
{
|
||||
RELEASE(string);
|
||||
RELEASE(locale);
|
||||
TEST_RELEASE(locale);
|
||||
RELEASE(charactersToBeSkipped);
|
||||
[super dealloc];
|
||||
}
|
||||
|
@ -74,16 +116,19 @@
|
|||
* For internal use only.
|
||||
*/
|
||||
- (BOOL) _scanCharactersFromSet: (NSCharacterSet *)set
|
||||
intoString: (NSString **)value;
|
||||
intoString: (NSString **)value;
|
||||
{
|
||||
unsigned int start;
|
||||
unsigned int start;
|
||||
BOOL (*memImp)(NSCharacterSet*, SEL, unichar);
|
||||
|
||||
if (scanLocation >= len)
|
||||
return NO;
|
||||
memImp = (BOOL (*)(NSCharacterSet*, SEL, unichar))
|
||||
[set methodForSelector: memSel];
|
||||
start = scanLocation;
|
||||
while (scanLocation < len)
|
||||
{
|
||||
if (![set characterIsMember: [string characterAtIndex: scanLocation]])
|
||||
if ((*memImp)(set, memSel, charAtIndex(scanLocation)) == NO)
|
||||
break;
|
||||
scanLocation++;
|
||||
}
|
||||
|
@ -153,21 +198,24 @@
|
|||
BOOL got_digits = NO;
|
||||
|
||||
/* Check for sign */
|
||||
switch ([string characterAtIndex: scanLocation])
|
||||
if (scanLocation < len)
|
||||
{
|
||||
case '+':
|
||||
scanLocation++;
|
||||
break;
|
||||
case '-':
|
||||
negative = YES;
|
||||
scanLocation++;
|
||||
break;
|
||||
switch (charAtIndex(scanLocation))
|
||||
{
|
||||
case '+':
|
||||
scanLocation++;
|
||||
break;
|
||||
case '-':
|
||||
negative = YES;
|
||||
scanLocation++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process digits */
|
||||
while (scanLocation < len)
|
||||
{
|
||||
unichar digit = [string characterAtIndex: scanLocation];
|
||||
unichar digit = charAtIndex(scanLocation);
|
||||
if ((digit < '0') || (digit > '9'))
|
||||
break;
|
||||
if (!overflow) {
|
||||
|
@ -185,7 +233,8 @@
|
|||
return NO;
|
||||
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;
|
||||
else if (negative)
|
||||
*value = -num;
|
||||
|
@ -212,7 +261,9 @@
|
|||
* Scan an unsigned int of the given radix into value.
|
||||
* 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 numLimit, digitLimit, digitValue;
|
||||
|
@ -226,44 +277,45 @@
|
|||
/* Process digits */
|
||||
while (scanLocation < len)
|
||||
{
|
||||
unichar digit = [string characterAtIndex: scanLocation];
|
||||
unichar digit = charAtIndex(scanLocation);
|
||||
switch (digit)
|
||||
{
|
||||
case '0': digitValue = 0; break;
|
||||
case '1': digitValue = 1; break;
|
||||
case '2': digitValue = 2; break;
|
||||
case '3': digitValue = 3; break;
|
||||
case '4': digitValue = 4; break;
|
||||
case '5': digitValue = 5; break;
|
||||
case '6': digitValue = 6; break;
|
||||
case '7': digitValue = 7; break;
|
||||
case '8': digitValue = 8; break;
|
||||
case '9': digitValue = 9; break;
|
||||
case 'a': digitValue = 0xA; break;
|
||||
case 'b': digitValue = 0xB; break;
|
||||
case 'c': digitValue = 0xC; break;
|
||||
case 'd': digitValue = 0xD; break;
|
||||
case 'e': digitValue = 0xE; break;
|
||||
case 'f': digitValue = 0xF; break;
|
||||
case 'A': digitValue = 0xA; break;
|
||||
case 'B': digitValue = 0xB; break;
|
||||
case 'C': digitValue = 0xC; break;
|
||||
case 'D': digitValue = 0xD; break;
|
||||
case 'E': digitValue = 0xE; break;
|
||||
case 'F': digitValue = 0xF; break;
|
||||
default:
|
||||
digitValue = radix;
|
||||
break;
|
||||
case '0': digitValue = 0; break;
|
||||
case '1': digitValue = 1; break;
|
||||
case '2': digitValue = 2; break;
|
||||
case '3': digitValue = 3; break;
|
||||
case '4': digitValue = 4; break;
|
||||
case '5': digitValue = 5; break;
|
||||
case '6': digitValue = 6; break;
|
||||
case '7': digitValue = 7; break;
|
||||
case '8': digitValue = 8; break;
|
||||
case '9': digitValue = 9; break;
|
||||
case 'a': digitValue = 0xA; break;
|
||||
case 'b': digitValue = 0xB; break;
|
||||
case 'c': digitValue = 0xC; break;
|
||||
case 'd': digitValue = 0xD; break;
|
||||
case 'e': digitValue = 0xE; break;
|
||||
case 'f': digitValue = 0xF; break;
|
||||
case 'A': digitValue = 0xA; break;
|
||||
case 'B': digitValue = 0xB; break;
|
||||
case 'C': digitValue = 0xC; break;
|
||||
case 'D': digitValue = 0xD; break;
|
||||
case 'E': digitValue = 0xE; break;
|
||||
case 'F': digitValue = 0xF; break;
|
||||
default:
|
||||
digitValue = radix;
|
||||
break;
|
||||
}
|
||||
if (digitValue >= radix)
|
||||
break;
|
||||
if (!overflow)
|
||||
{
|
||||
if ((num > numLimit) || ((num == numLimit) && (digitValue > digitLimit)))
|
||||
overflow = YES;
|
||||
else
|
||||
num = num * radix + digitValue;
|
||||
}
|
||||
if ((num > numLimit)
|
||||
|| ((num == numLimit) && (digitValue > digitLimit)))
|
||||
overflow = YES;
|
||||
else
|
||||
num = num * radix + digitValue;
|
||||
}
|
||||
scanLocation++;
|
||||
gotDigits = YES;
|
||||
}
|
||||
|
@ -302,23 +354,23 @@
|
|||
|
||||
/* Check radix */
|
||||
radix = 10;
|
||||
if ((scanLocation < len) && ([string characterAtIndex: scanLocation] == '0'))
|
||||
if ((scanLocation < len) && (charAtIndex(scanLocation) == '0'))
|
||||
{
|
||||
radix = 8;
|
||||
scanLocation++;
|
||||
gotDigits = YES;
|
||||
if (scanLocation < len)
|
||||
{
|
||||
switch ([string characterAtIndex: scanLocation])
|
||||
radix = 8;
|
||||
scanLocation++;
|
||||
gotDigits = YES;
|
||||
if (scanLocation < len)
|
||||
{
|
||||
case 'x':
|
||||
case 'X':
|
||||
scanLocation++;
|
||||
radix = 16;
|
||||
gotDigits = NO;
|
||||
break;
|
||||
switch (charAtIndex(scanLocation))
|
||||
{
|
||||
case 'x':
|
||||
case 'X':
|
||||
scanLocation++;
|
||||
radix = 16;
|
||||
gotDigits = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( [self scanUnsignedInt_: value radix: radix gotDigits: gotDigits])
|
||||
return YES;
|
||||
|
@ -367,21 +419,24 @@
|
|||
}
|
||||
|
||||
/* Check for sign */
|
||||
switch ([string characterAtIndex: scanLocation])
|
||||
if (scanLocation < len)
|
||||
{
|
||||
case '+':
|
||||
scanLocation++;
|
||||
break;
|
||||
case '-':
|
||||
negative = YES;
|
||||
scanLocation++;
|
||||
break;
|
||||
switch (charAtIndex(scanLocation))
|
||||
{
|
||||
case '+':
|
||||
scanLocation++;
|
||||
break;
|
||||
case '-':
|
||||
negative = YES;
|
||||
scanLocation++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process digits */
|
||||
while (scanLocation < len)
|
||||
{
|
||||
unichar digit = [string characterAtIndex: scanLocation];
|
||||
unichar digit = charAtIndex(scanLocation);
|
||||
if ((digit < '0') || (digit > '9'))
|
||||
break;
|
||||
if (!overflow) {
|
||||
|
@ -431,14 +486,14 @@
|
|||
*/
|
||||
- (BOOL) scanDouble: (double *)value
|
||||
{
|
||||
unichar decimal;
|
||||
unichar c = 0;
|
||||
double num = 0.0;
|
||||
long int exponent = 0;
|
||||
BOOL negative = NO;
|
||||
BOOL got_dot = NO;
|
||||
BOOL got_digit = NO;
|
||||
unsigned int saveScanLocation = scanLocation;
|
||||
unichar decimal = '.';
|
||||
unichar c = 0;
|
||||
double num = 0.0;
|
||||
long int exponent = 0;
|
||||
BOOL negative = NO;
|
||||
BOOL got_dot = NO;
|
||||
BOOL got_digit = NO;
|
||||
unsigned int saveScanLocation = scanLocation;
|
||||
|
||||
/* Skip whitespace */
|
||||
if (![self _skipToNextField])
|
||||
|
@ -448,28 +503,36 @@
|
|||
}
|
||||
|
||||
/*
|
||||
* FIXME: Should get decimal point character from locale.
|
||||
* The key is NSDecimalSeparator.
|
||||
* The problem is that I can't find anything in GNUSTEP about locales.
|
||||
* Get decimal point character from locale if necessary.
|
||||
*/
|
||||
decimal = '.';
|
||||
if (locale != nil)
|
||||
{
|
||||
NSString *pointString;
|
||||
|
||||
pointString = [locale objectForKey: NSDecimalSeparator];
|
||||
if ([pointString length] > 0)
|
||||
decimal = [pointString characterAtIndex: 0];
|
||||
}
|
||||
|
||||
/* Check for sign */
|
||||
switch ([string characterAtIndex: scanLocation])
|
||||
if (scanLocation < len)
|
||||
{
|
||||
case '+':
|
||||
scanLocation++;
|
||||
break;
|
||||
case '-':
|
||||
negative = YES;
|
||||
scanLocation++;
|
||||
break;
|
||||
switch (charAtIndex(scanLocation))
|
||||
{
|
||||
case '+':
|
||||
scanLocation++;
|
||||
break;
|
||||
case '-':
|
||||
negative = YES;
|
||||
scanLocation++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process number */
|
||||
while (scanLocation < len)
|
||||
{
|
||||
c = [string characterAtIndex: scanLocation];
|
||||
c = charAtIndex(scanLocation);
|
||||
if ((c >= '0') && (c <= '9'))
|
||||
{
|
||||
/* Ensure that the number being accumulated will not overflow. */
|
||||
|
@ -499,53 +562,53 @@
|
|||
}
|
||||
scanLocation++;
|
||||
}
|
||||
if (!got_digit)
|
||||
{
|
||||
scanLocation = saveScanLocation;
|
||||
return NO;
|
||||
}
|
||||
if (!got_digit)
|
||||
{
|
||||
scanLocation = saveScanLocation;
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* Check for trailing exponent */
|
||||
if ((scanLocation < len) && ((c == 'e') || (c == 'E')))
|
||||
{
|
||||
int expval;
|
||||
/* Check for trailing exponent */
|
||||
if ((scanLocation < len) && ((c == 'e') || (c == 'E')))
|
||||
{
|
||||
int expval;
|
||||
|
||||
scanLocation++;
|
||||
if ([self _scanInt: &expval])
|
||||
scanLocation++;
|
||||
if ([self _scanInt: &expval])
|
||||
{
|
||||
/* Check for exponent overflow */
|
||||
if (num)
|
||||
{
|
||||
/* Check for exponent overflow */
|
||||
if (num)
|
||||
{
|
||||
if ((exponent > 0) && (expval > (LONG_MAX - exponent)))
|
||||
exponent = LONG_MAX;
|
||||
else if ((exponent < 0) && (expval < (LONG_MIN - exponent)))
|
||||
exponent = LONG_MIN;
|
||||
else
|
||||
exponent += expval;
|
||||
}
|
||||
if ((exponent > 0) && (expval > (LONG_MAX - exponent)))
|
||||
exponent = LONG_MAX;
|
||||
else if ((exponent < 0) && (expval < (LONG_MIN - exponent)))
|
||||
exponent = LONG_MIN;
|
||||
else
|
||||
exponent += expval;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _ACCEPT_BAD_EXPONENTS_
|
||||
/* Numbers like 1.23eFOO are accepted (as 1.23). */
|
||||
scanLocation = expScanLocation;
|
||||
/* Numbers like 1.23eFOO are accepted (as 1.23). */
|
||||
scanLocation = expScanLocation;
|
||||
#else
|
||||
/* Numbers like 1.23eFOO are rejected. */
|
||||
scanLocation = saveScanLocation;
|
||||
return NO;
|
||||
/* Numbers like 1.23eFOO are rejected. */
|
||||
scanLocation = saveScanLocation;
|
||||
return NO;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (value)
|
||||
{
|
||||
if (num && exponent)
|
||||
num *= pow(10.0, (double) exponent);
|
||||
if (negative)
|
||||
*value = -num;
|
||||
else
|
||||
*value = num;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
if (value)
|
||||
{
|
||||
if (num && exponent)
|
||||
num *= pow(10.0, (double) exponent);
|
||||
if (negative)
|
||||
*value = -num;
|
||||
else
|
||||
*value = num;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -577,7 +640,7 @@
|
|||
* containing the scanned characters is returned by reference in value.
|
||||
*/
|
||||
- (BOOL) scanCharactersFromSet: (NSCharacterSet *)aSet
|
||||
intoString: (NSString **)value;
|
||||
intoString: (NSString **)value;
|
||||
{
|
||||
unsigned int saveScanLocation = scanLocation;
|
||||
|
||||
|
@ -598,15 +661,18 @@
|
|||
- (BOOL) scanUpToCharactersFromSet: (NSCharacterSet *)set
|
||||
intoString: (NSString **)value;
|
||||
{
|
||||
unsigned int saveScanLocation = scanLocation;
|
||||
unsigned int start;
|
||||
unsigned int saveScanLocation = scanLocation;
|
||||
unsigned int start;
|
||||
BOOL (*memImp)(NSCharacterSet*, SEL, unichar);
|
||||
|
||||
if (![self _skipToNextField])
|
||||
return NO;
|
||||
start = scanLocation;
|
||||
memImp = (BOOL (*)(NSCharacterSet*, SEL, unichar))
|
||||
[set methodForSelector: memSel];
|
||||
while (scanLocation < len)
|
||||
{
|
||||
if ([set characterIsMember: [string characterAtIndex: scanLocation]])
|
||||
if ((*memImp)(set, memSel, charAtIndex(scanLocation)) == YES)
|
||||
break;
|
||||
scanLocation++;
|
||||
}
|
||||
|
@ -644,8 +710,8 @@
|
|||
if (range.location + range.length > len)
|
||||
return NO;
|
||||
range = [string rangeOfString: aString
|
||||
options: caseSensitive ? 0 : NSCaseInsensitiveSearch
|
||||
range: range];
|
||||
options: caseSensitive ? 0 : NSCaseInsensitiveSearch
|
||||
range: range];
|
||||
if (range.length == 0)
|
||||
{
|
||||
scanLocation = saveScanLocation;
|
||||
|
@ -675,8 +741,8 @@
|
|||
range.location = scanLocation;
|
||||
range.length = len - scanLocation;
|
||||
found = [string rangeOfString: aString
|
||||
options: caseSensitive ? 0 : NSCaseInsensitiveSearch
|
||||
range: range];
|
||||
options: caseSensitive ? 0 : NSCaseInsensitiveSearch
|
||||
range: range];
|
||||
if (found.length)
|
||||
range.length = found.location - scanLocation;
|
||||
if (range.length == 0)
|
||||
|
@ -768,7 +834,7 @@
|
|||
*/
|
||||
- (void) setLocale: (NSDictionary *)localeDictionary
|
||||
{
|
||||
locale = RETAIN(localeDictionary);
|
||||
ASSIGN(locale, localeDictionary);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue