Apply some optimisation

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@27950 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2009-02-22 20:01:53 +00:00
parent 77909754b5
commit 26789c7a45
3 changed files with 224 additions and 91 deletions

View file

@ -3,6 +3,7 @@
* Source/NSUnarchiver.m: * Source/NSUnarchiver.m:
make float and double interchangable to cope with MacOS-X 10.5 make float and double interchangable to cope with MacOS-X 10.5
API which can use either for CGFloat. API which can use either for CGFloat.
* Source/NSXMLParser.m: optimize sloppy parser somewhat.
2009-02-21 Richard Frith-Macdonald <rfm@gnu.org> 2009-02-21 Richard Frith-Macdonald <rfm@gnu.org>

View file

@ -34,8 +34,13 @@
/* These typedefs must be in place before GSObjCRuntime.h is imported. /* These typedefs must be in place before GSObjCRuntime.h is imported.
*/ */
typedef gsaddr NSInteger; typedef intptr_t NSInteger;
typedef gsuaddr NSUInteger; typedef uintptr_t NSUInteger;
#if GS_SIZEOF_VOIDP == 8
typedef double CGFloat;
#else
typedef float CGFloat;
#endif
#define NSINTEGER_DEFINED 1 #define NSINTEGER_DEFINED 1

View file

@ -594,7 +594,8 @@ static NSNull *null = nil;
@end @end
static NSString *UTF8STR(const void *ptr, int len) static inline NSString *
NewUTF8STR(const void *ptr, int len)
{ {
NSString *s; NSString *s;
@ -603,7 +604,7 @@ static NSString *UTF8STR(const void *ptr, int len)
encoding: NSUTF8StringEncoding]; encoding: NSUTF8StringEncoding];
if (s == nil) if (s == nil)
NSLog(@"could not convert to UTF8 string! bytes=%08x len=%d", ptr, len); NSLog(@"could not convert to UTF8 string! bytes=%08x len=%d", ptr, len);
return AUTORELEASE(s); return s;
} }
typedef struct NSXMLParserIvarsType typedef struct NSXMLParserIvarsType
@ -621,8 +622,20 @@ typedef struct NSXMLParserIvarsType
BOOL shouldReportNamespacePrefixes; BOOL shouldReportNamespacePrefixes;
BOOL shouldResolveExternalEntities; BOOL shouldResolveExternalEntities;
BOOL acceptHTML; // be lazy with bad tag nesting BOOL acceptHTML; // be lazy with bad tag nesting
IMP didEndElement;
IMP didEndMappingPrefix;
IMP didStartElement;
IMP didStartMappingPrefix;
IMP foundCharacters;
} NSXMLParserIvars; } NSXMLParserIvars;
static SEL didEndElementSel = 0;
static SEL didEndMappingPrefixSel;
static SEL didStartElementSel;
static SEL didStartMappingPrefixSel;
static SEL foundCharactersSel;
@implementation SloppyXMLParser @implementation SloppyXMLParser
#define EXTRA_DEBUG 0 #define EXTRA_DEBUG 0
@ -630,7 +643,7 @@ typedef struct NSXMLParserIvarsType
typedef struct { @defs(NSXMLParser) } *xp; typedef struct { @defs(NSXMLParser) } *xp;
#define _parser (((xp)self)->_parser) #define _parser (((xp)self)->_parser)
#define _handler (((xp)self)->_handler) #define _handler (((xp)self)->_handler)
#define this ((NSXMLParserIvars*)_parser) #define this ((NSXMLParserIvars*)_parser)
#define _del ((id)_handler) #define _del ((id)_handler)
+ (void) initialize + (void) initialize
@ -639,6 +652,19 @@ typedef struct { @defs(NSXMLParser) } *xp;
{ {
null = RETAIN([NSNull null]); null = RETAIN([NSNull null]);
} }
if (didEndElementSel == 0)
{
didEndElementSel
= @selector(parser:didEndElement:namespaceURI:qualifiedName:);
didEndMappingPrefixSel
= @selector(parser:didEndMappingPrefix:);
didStartElementSel
= @selector(parser:didStartElement:namespaceURI:qualifiedName:attributes:);
didStartMappingPrefixSel
= @selector(parser:didStartMappingPrefix:toURI:);
foundCharactersSel
= @selector(parser:foundCharacters:);
}
} }
- (void) abortParsing - (void) abortParsing
@ -706,7 +732,58 @@ typedef struct { @defs(NSXMLParser) } *xp;
- (void) setDelegate: (id)delegate - (void) setDelegate: (id)delegate
{ {
_handler = delegate; if (_handler != delegate)
{
_handler = delegate;
if ([_del respondsToSelector: didEndElementSel])
{
this->didEndElement = [_del methodForSelector: didEndElementSel];
}
else
{
this->didEndElement = 0;
}
if ([_del respondsToSelector: didEndMappingPrefixSel])
{
this->didEndMappingPrefix
= [_del methodForSelector: didEndMappingPrefixSel];
}
else
{
this->didEndMappingPrefix = 0;
}
if ([_del respondsToSelector: didStartElementSel])
{
this->didStartElement = [_del methodForSelector: didStartElementSel];
}
else
{
this->didStartElement = 0;
}
if ([_del respondsToSelector: didStartMappingPrefixSel])
{
this->didStartMappingPrefix
= [_del methodForSelector: didStartMappingPrefixSel];
}
else
{
this->didStartMappingPrefix = 0;
}
if ([_del respondsToSelector: foundCharactersSel])
{
this->foundCharacters
= [_del methodForSelector: foundCharactersSel];
}
else
{
this->foundCharacters = 0;
}
}
} }
- (NSError *) parserError - (NSError *) parserError
@ -759,8 +836,7 @@ typedef struct { @defs(NSXMLParser) } *xp;
{ {
NSString *tag = [this->tagPath lastObject]; NSString *tag = [this->tagPath lastObject];
if ([_del respondsToSelector: if (this->didEndElement != 0)
@selector(parser:didEndElement:namespaceURI:qualifiedName:)])
{ {
NSString *qualified = nil; NSString *qualified = nil;
NSString *uri = nil; NSString *uri = nil;
@ -778,16 +854,13 @@ typedef struct { @defs(NSXMLParser) } *xp;
} }
uri = [self _uriForPrefix: p]; uri = [self _uriForPrefix: p];
} }
[_del parser: self (*this->didEndElement)(_del,
didEndElement: tag didEndElementSel, self, tag, uri, qualified);
namespaceURI: uri
qualifiedName: qualified];
} }
if (this->shouldReportNamespacePrefixes) if (this->shouldReportNamespacePrefixes)
{ {
if ([_del respondsToSelector: if (this->didEndMappingPrefix != 0)
@selector(parser:didEndMappingPrefix:)])
{ {
id d = [this->namespaces lastObject]; id d = [this->namespaces lastObject];
@ -798,7 +871,8 @@ typedef struct { @defs(NSXMLParser) } *xp;
while ((k = [e nextObject]) != nil) while ((k = [e nextObject]) != nil)
{ {
[_del parser: self didEndMappingPrefix: k]; (*this->didEndMappingPrefix)(_del,
didEndMappingPrefixSel, self, k);
} }
} }
} }
@ -885,10 +959,10 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
{ {
if (ns == nil) if (ns == nil)
{ {
ns = [NSMutableDictionary dictionary]; ns = [NSMutableDictionary new];
if (this->shouldProcessNamespaces) if (this->shouldProcessNamespaces)
{ {
attr = AUTORELEASE([attributes mutableCopy]); attr = [attributes mutableCopy];
} }
} }
uri = [attributes objectForKey: k]; uri = [attributes objectForKey: k];
@ -899,12 +973,10 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
} }
if (this->shouldReportNamespacePrefixes) if (this->shouldReportNamespacePrefixes)
{ {
if ([_del respondsToSelector: if (this->didStartMappingPrefix != 0)
@selector(parser:didStartMappingPrefix:toURI:)])
{ {
[_del parser: self (*this->didStartMappingPrefix)(_del,
didStartMappingPrefix: prefix didStartMappingPrefixSel, self, prefix, uri);
toURI: uri];
} }
} }
if (attr != nil) if (attr != nil)
@ -917,9 +989,8 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
[this->tagPath addObject: tag]; [this->tagPath addObject: tag];
[this->namespaces addObject: ((ns == nil) ? (id)null : (id)ns)]; [this->namespaces addObject: ((ns == nil) ? (id)null : (id)ns)];
if ([_del respondsToSelector: if (this->didStartElement != 0)
@selector(parser:didStartElement:namespaceURI:qualifiedName:attributes:)]) {
{
if (this->shouldProcessNamespaces) if (this->shouldProcessNamespaces)
{ {
NSRange r = [tag rangeOfString: @":"]; NSRange r = [tag rangeOfString: @":"];
@ -938,12 +1009,11 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
qualified = nil; qualified = nil;
uri = nil; uri = nil;
} }
[_del parser: self (*this->didStartElement)(_del,
didStartElement: tag didStartElementSel, self, tag, uri, qualified, attributes);
namespaceURI: uri
qualifiedName: qualified
attributes: attributes];
} }
if (ns != nil) [ns release];
if (attr != nil) [attr release];
} }
} }
else else
@ -969,14 +1039,12 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
[this->tagPath lastObject], tag]]; [this->tagPath lastObject], tag]];
return; return;
} }
[self _closeLastTag]; [self _closeLastTag];
} }
} }
- (NSString *) _entity - (BOOL) _parseEntity: (NSString**)result
{ {
// parse &xxx; sequence
int c; int c;
const unsigned char *ep = this->cp; // should be position behind & const unsigned char *ep = this->cp; // should be position behind &
int len; int len;
@ -988,76 +1056,123 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
} while (c != EOF && c != '<' && c != ';'); } while (c != EOF && c != '<' && c != ';');
if (c != ';') if (c != ';')
return nil; // invalid sequence - end of file or missing ; before next tag {
// invalid sequence - end of file or missing ; before next tag
return NO;
}
len = this->cp - ep - 1; len = this->cp - ep - 1;
if (*ep == '#') if (*ep == '#')
{ {
// &#ddd; or &#xhh; // &#ddd; or &#xhh;
// !!! ep+1 is not 0-terminated - but by ;!! // !!! ep+1 is not 0-terminated - but by ;!!
if (sscanf((char *)ep+1, "x%x;", &val)) if (sscanf((char *)ep+1, "x%x;", &val))
return [NSString stringWithFormat: @"%C", val]; // &#xhh; hex value {
else if (sscanf((char *)ep+1, "%d;", &val)) // &#xhh; hex value
return [NSString stringWithFormat: @"%C", val]; // &ddd; decimal value if (result != 0)
{
*result = [[NSString alloc] initWithFormat: @"%C", val];
}
return YES;
}
else if (sscanf((char *)ep+1, "%d;", &val))
{
// &ddd; decimal value
if (result != 0)
{
*result = [[NSString alloc] initWithFormat: @"%C", val];
}
return YES;
}
} }
else else
{ {
// the five predefined entities // the five predefined entities
if (len == 3 && strncmp((char *)ep, "amp", len) == 0) if (len == 3 && strncmp((char *)ep, "amp", len) == 0)
return @"&"; {
if (len == 2 && strncmp((char *)ep, "lt", len) == 0) if (result != 0) *result = @"&";
return @"<"; return YES;
if (len == 2 && strncmp((char *)ep, "gt", len) == 0) }
return @">"; else if (len == 2 && strncmp((char *)ep, "lt", len) == 0)
if (len == 4 && strncmp((char *)ep, "quot", len) == 0) {
return @"\""; if (result != 0) *result = @"<";
if (len == 4 && strncmp((char *)ep, "apos", len) == 0) return YES;
return @"'"; }
else if (len == 2 && strncmp((char *)ep, "gt", len) == 0)
{
if (result != 0) *result = @">";
return YES;
}
else if (len == 4 && strncmp((char *)ep, "quot", len) == 0)
{
if (result != 0) *result = @"\"";
return YES;
}
else if (len == 4 && strncmp((char *)ep, "apos", len) == 0)
{
if (result != 0) *result = @"'";
return YES;
}
} }
entity = UTF8STR(ep, len); entity = NewUTF8STR(ep, len);
#if 1 #if 1
NSLog(@"NSXMLParser: unrecognized entity: &%@;", entity); NSLog(@"NSXMLParser: unrecognized entity: &%@;", entity);
#endif #endif
// entity=[entitiesTable objectForKey: entity]; // look up string in entity translation table // entity=[entitiesTable objectForKey: entity]; // look up string in entity translation table
if (!entity)
entity=@"&??;"; // unknown entity if (entity == nil)
return entity; {
entity = @"&??;"; // unknown entity
}
if (result != 0)
{
*result = entity;
}
return YES;
} }
- (NSString *) _qarg - (NSString *) _newQarg
{ {
// get argument (might be quoted) // get argument (might be quoted)
const unsigned char *ap = --this->cp; // argument start pointer const unsigned char *ap = --this->cp; // argument start pointer
int c = cget(); // refetch first character int c = cget(); // refetch first character
#if EXTRA_DEBUG #if EXTRA_DEBUG
NSLog(@"_qarg: %02x %c", c, isprint(c)?c: ' '); NSLog(@"_newQarg: %02x %c", c, isprint(c)?c: ' ');
#endif #endif
if (c == '\"') if (c == '\"')
{ {
// quoted argument do
do { {
c = cget(); c = cget();
if (c == EOF) if (c == EOF)
return nil; // unterminated! {
} while (c != '\"'); return nil; // unterminated!
return UTF8STR(ap + 1, this->cp - ap - 2); }
}
while (c != '\"');
return NewUTF8STR(ap + 1, this->cp - ap - 2);
} }
if (c == '\'') if (c == '\'')
{ {
// apostrophed argument do
do { {
c = cget(); c = cget();
if (c == EOF) if (c == EOF)
return nil; // unterminated! {
} while (c != '\''); return nil; // unterminated!
return UTF8STR(ap + 1, this->cp - ap - 2); }
}
while (c != '\'');
return NewUTF8STR(ap + 1, this->cp - ap - 2);
} }
if (!this->acceptHTML) if (!this->acceptHTML)
; // strict XML requires quoting (?) ; // strict XML requires quoting (?)
while (!isspace(c) && c != '>' && c != '/' && c != '?' && c != '=' &&c != EOF) while (!isspace(c) && c != '>' && c != '/' && c != '?' && c != '=' &&c != EOF)
c = cget(); c = cget();
this->cp--; // go back to terminating character this->cp--; // go back to terminating character
return UTF8STR(ap, this->cp - ap); return NewUTF8STR(ap, this->cp - ap);
} }
- (BOOL) parse - (BOOL) parse
@ -1100,11 +1215,14 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
/* check for whitespace only - might set/reset /* check for whitespace only - might set/reset
* a flag to indicate so * a flag to indicate so
*/ */
if ([_del respondsToSelector: if (this->foundCharacters != 0)
@selector(parser:foundCharacters:)])
{ {
[_del parser: self foundCharacters: NSString *s;
UTF8STR(vp, this->cp - vp - 1)];
s = NewUTF8STR(vp, this->cp - vp - 1);
(*this->foundCharacters)(_del,
foundCharactersSel, self, s);
[s release];
} }
vp = this->cp; vp = this->cp;
} }
@ -1130,12 +1248,11 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
while ([this->tagPath count] > 0) while ([this->tagPath count] > 0)
{ {
// lazily close all open tags // lazily close all open tags
if ([_del respondsToSelector: if (this->didEndElement != 0)
@selector(parser:didEndElement:namespaceURI:qualifiedName:)])
{ {
[_del parser: self (*this->didEndElement)(_del,
didEndElement: [this->tagPath lastObject] didEndElementSel, self,
namespaceURI: nil qualifiedName: nil]; [this->tagPath lastObject], nil, nil);
} }
[this->tagPath removeLastObject]; // pop from stack [this->tagPath removeLastObject]; // pop from stack
} }
@ -1153,16 +1270,18 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
case '&': case '&':
{ {
NSString *entity = [self _entity]; NSString *entity;
if (!entity) if ([self _parseEntity: &entity] == NO)
{ {
return [self _parseError: @"empty entity name"]; return [self _parseError: @"empty entity name"];
} }
if ([_del respondsToSelector: @selector(parser:foundCharacters:)]) if (this->foundCharacters != 0)
{ {
[_del parser: self foundCharacters: entity]; (*this->foundCharacters)(_del,
foundCharactersSel, self, entity);
} }
[entity release];
vp = this->cp; // next value sequence starts here vp = this->cp; // next value sequence starts here
c = cget(); // first character behind ; c = cget(); // first character behind ;
continue; continue;
@ -1189,7 +1308,7 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
/* if _del responds to parser: foundComment: /* if _del responds to parser: foundComment:
* convert to string (tp+4 ... cp) * convert to string (tp+4 ... cp)
*/ */
this->cp+=3; // might go beyond cend but does not care this->cp += 3; // might go beyond cend but does not care
vp = this->cp; // value might continue vp = this->cp; // value might continue
c = cget(); // get first character behind comment c = cget(); // get first character behind comment
continue; continue;
@ -1212,6 +1331,7 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
* and quoted string constants... * and quoted string constants...
*/ */
} }
while (c != EOF && !isspace(c) while (c != EOF && !isspace(c)
&& c != '>' && c != '/' && c != '?') && c != '>' && c != '/' && c != '?')
{ {
@ -1219,16 +1339,16 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
} }
if (*tp == '/') if (*tp == '/')
{ {
tag = UTF8STR(tp + 1, this->cp - tp - 2); tag = NewUTF8STR(tp + 1, this->cp - tp - 2);
} }
else else
{ {
tag = UTF8STR(tp, this->cp - tp - 1); tag = NewUTF8STR(tp, this->cp - tp - 1);
} }
#if EXTRA_DEBUG #if EXTRA_DEBUG
NSLog(@"tag=%@ - %02x %c", tag, c, isprint(c)?c: ' '); NSLog(@"tag=%@ - %02x %c", tag, c, isprint(c)?c: ' ');
#endif #endif
parameters = [NSMutableDictionary dictionaryWithCapacity: 5]; parameters = [[NSMutableDictionary alloc] initWithCapacity: 5];
while (isspace(c)) while (isspace(c))
{ {
c = cget(); c = cget();
@ -1279,7 +1399,7 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
} }
/* get next argument (eats up to /, ?, >, =, space) /* get next argument (eats up to /, ?, >, =, space)
*/ */
arg = [self _qarg]; arg = [self _newQarg];
#if EXTRA_DEBUG #if EXTRA_DEBUG
NSLog(@"arg=%@", arg); NSLog(@"arg=%@", arg);
#endif #endif
@ -1290,16 +1410,23 @@ NSLog(@"_processTag <%@%@ %@>", flag?@"/": @"", tag, attributes);
c = cget(); // get delimiting character c = cget(); // get delimiting character
if (c == '=') if (c == '=')
{ {
NSString *val;
// explicit assignment // explicit assignment
c = cget(); // skip = c = cget(); // skip =
[parameters setObject: [self _qarg] forKey: arg]; val = [self _newQarg];
[parameters setObject: val forKey: arg];
[val release];
c = cget(); // get character behind qarg value c = cget(); // get character behind qarg value
} }
else // implicit else // implicit
{ {
[parameters setObject: @"" forKey: arg]; [parameters setObject: @"" forKey: arg];
} }
[arg release];
} }
[parameters release];
[tag release];
vp = this->cp; // prepare for next value vp = this->cp; // prepare for next value
c = cget(); // skip > and fetch next character c = cget(); // skip > and fetch next character
} }