Просмотр исходного кода

Optimize FLEXTypeEncodingParser

Tanner Bennett лет назад: 6
Родитель
Сommit
4a4a08df16
1 измененных файлов с 166 добавлено и 100 удалено
  1. 166 100
      Classes/Utility/Runtime/FLEXTypeEncodingParser.m

+ 166 - 100
Classes/Utility/Runtime/FLEXTypeEncodingParser.m

@@ -37,6 +37,7 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
 @property (nonatomic, readonly) NSScanner *scan;
 @property (nonatomic, readonly) NSScanner *scan;
 @property (nonatomic, readonly) NSString *scanned;
 @property (nonatomic, readonly) NSString *scanned;
 @property (nonatomic, readonly) NSString *unscanned;
 @property (nonatomic, readonly) NSString *unscanned;
+@property (nonatomic, readonly) char nextChar;
 
 
 /// Replacements are made to this string as we scan as needed
 /// Replacements are made to this string as we scan as needed
 @property (nonatomic) NSMutableString *cleaned;
 @property (nonatomic) NSMutableString *cleaned;
@@ -150,6 +151,11 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
     return identifierSet;
     return identifierSet;
 }
 }
 
 
+- (char)nextChar {
+    NSScanner *scan = self.scan;
+    return [scan.string characterAtIndex:scan.scanLocation];
+}
+
 /// For scanning struct/class names
 /// For scanning struct/class names
 - (NSString *)scanIdentifier {
 - (NSString *)scanIdentifier {
     NSString *prefix = nil, *suffix = nil;
     NSString *prefix = nil, *suffix = nil;
@@ -250,45 +256,52 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
     }
     }
 
 
     // Check for struct/union/array
     // Check for struct/union/array
-    if ([self canScanChar:FLEXTypeEncodingStructBegin] ||
-      [self canScanChar:FLEXTypeEncodingUnionBegin] ||
-      [self canScanChar:FLEXTypeEncodingArrayBegin]) {
+    char next = self.nextChar;
+    BOOL didScanSUA = YES, structOrUnion = NO, isUnion = NO;
+    FLEXTypeEncoding opening = FLEXTypeEncodingNull, closing = FLEXTypeEncodingNull;
+    switch (next) {
+        case FLEXTypeEncodingStructBegin:
+            structOrUnion = YES;
+            opening = FLEXTypeEncodingStructBegin;
+            closing = FLEXTypeEncodingStructEnd;
+            break;
+        case FLEXTypeEncodingUnionBegin:
+            structOrUnion = isUnion = YES;
+            opening = FLEXTypeEncodingUnionBegin;
+            closing = FLEXTypeEncodingUnionEnd;
+            break;
+        case FLEXTypeEncodingArrayBegin:
+            opening = FLEXTypeEncodingArrayBegin;
+            closing = FLEXTypeEncodingArrayEnd;
+            break;
+            
+        default:
+            didScanSUA = NO;
+            break;
+    }
+    
+    if (didScanSUA) {
         NSUInteger backup = self.scan.scanLocation;
         NSUInteger backup = self.scan.scanLocation;
 
 
         // Ensure we have a closing tag
         // Ensure we have a closing tag
-        if (![self scanPair:FLEXTypeEncodingStructBegin close:FLEXTypeEncodingStructEnd] &&
-          ![self scanPair:FLEXTypeEncodingUnionBegin close:FLEXTypeEncodingUnionEnd] &&
-          ![self scanPair:FLEXTypeEncodingArrayBegin close:FLEXTypeEncodingArrayEnd]) {
+        if (![self scanPair:opening close:closing]) {
             // Scan failed, abort
             // Scan failed, abort
             self.scan.scanLocation = start;
             self.scan.scanLocation = start;
             return -1;
             return -1;
         }
         }
 
 
-        // Scan the next thing until we scan the closing tag
-        BOOL structOrUnion = NO, isUnion = NO;
+        // Move cursor just after opening tag (struct/union/array)
         NSInteger arrayCount = -1;
         NSInteger arrayCount = -1;
-        self.scan.scanLocation = backup;
-        FLEXTypeEncoding closing;
-        if ([self scanChar:FLEXTypeEncodingStructBegin]) {
-            closing = FLEXTypeEncodingStructEnd;
-            structOrUnion = YES;
-        } else if ([self scanChar:FLEXTypeEncodingUnionBegin]) {
-            closing = FLEXTypeEncodingUnionEnd;
-            structOrUnion = isUnion = YES;
-        } else {
-            // Assert because code above did confirm a closing tag exists
-            assert([self scanChar:FLEXTypeEncodingArrayBegin]);
-            closing = FLEXTypeEncodingArrayEnd;
-            
+        self.scan.scanLocation = backup + 1;
+        
+        if (!structOrUnion) {
             arrayCount = [self scanSize];
             arrayCount = [self scanSize];
             if (!arrayCount) {
             if (!arrayCount) {
                 // Arrays must have a count after the opening brace
                 // Arrays must have a count after the opening brace
                 self.scan.scanLocation = start;
                 self.scan.scanLocation = start;
                 return -1;
                 return -1;
             }
             }
-        }
-
-        if (structOrUnion) {
+        } else {
             // If we encounter the ?= portion of something like {?=b8b4b1b1b18[8S]}
             // If we encounter the ?= portion of something like {?=b8b4b1b1b18[8S]}
             // then we skip over it, since it means nothing to us in this context.
             // then we skip over it, since it means nothing to us in this context.
             // It is completely optional, and if it fails, we go right back where we were.
             // It is completely optional, and if it fails, we go right back where we were.
@@ -305,15 +318,18 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
         NSMutableString *cleanedBackup = self.cleaned.mutableCopy;
         NSMutableString *cleanedBackup = self.cleaned.mutableCopy;
         
         
         while (![self scanChar:closing]) {
         while (![self scanChar:closing]) {
+            next = self.nextChar;
             // Check for bitfields, which we cannot support because
             // Check for bitfields, which we cannot support because
             // type encodings for bitfields do not include alignment info
             // type encodings for bitfields do not include alignment info
-            if ([self scanChar:FLEXTypeEncodingBitField]) {
+            if (next == FLEXTypeEncodingBitField) {
                 self.scan.scanLocation = start;
                 self.scan.scanLocation = start;
                 return -1;
                 return -1;
             }
             }
 
 
             // Structure fields could be named
             // Structure fields could be named
-            [self scanPair:FLEXTypeEncodingQuote close:FLEXTypeEncodingQuote];
+            if (next == FLEXTypeEncodingQuote) {
+                [self scanPair:FLEXTypeEncodingQuote close:FLEXTypeEncodingQuote];
+            }
 
 
             ssize_t align = 0;
             ssize_t align = 0;
             ssize_t size = [self scanAndGetSizeAndAlignForNextType:&align];
             ssize_t size = [self scanAndGetSizeAndAlignForNextType:&align];
@@ -349,12 +365,12 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
             // arrays are element.size x length, and
             // arrays are element.size x length, and
             // structs are the sum of their members
             // structs are the sum of their members
             if (structOrUnion) {
             if (structOrUnion) {
-                if (isUnion) {
+                if (isUnion) { // Union
                     sizeSoFar = MAX(sizeSoFar, size);
                     sizeSoFar = MAX(sizeSoFar, size);
-                } else {
+                } else { // Struct
                     sizeSoFar += size;
                     sizeSoFar += size;
                 }
                 }
-            } else {
+            } else { // Array
                 sizeSoFar = size * arrayCount;
                 sizeSoFar = size * arrayCount;
             }
             }
             
             
@@ -370,46 +386,55 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
 
 
         return sizeSoFar;
         return sizeSoFar;
     }
     }
-
+    
     // Scan single thing and possible size and return
     // Scan single thing and possible size and return
     ssize_t size = 0;
     ssize_t size = 0;
-    FLEXTypeEncoding t;
-    if ([self scanChar:FLEXTypeEncodingUnknown into:&t] ||
-      [self scanChar:FLEXTypeEncodingChar into:&t] ||
-      [self scanChar:FLEXTypeEncodingInt into:&t] ||
-      [self scanChar:FLEXTypeEncodingShort into:&t] ||
-      [self scanChar:FLEXTypeEncodingLong into:&t] ||
-      [self scanChar:FLEXTypeEncodingLongLong into:&t] ||
-      [self scanChar:FLEXTypeEncodingUnsignedChar into:&t] ||
-      [self scanChar:FLEXTypeEncodingUnsignedInt into:&t] ||
-      [self scanChar:FLEXTypeEncodingUnsignedShort into:&t] ||
-      [self scanChar:FLEXTypeEncodingUnsignedLong into:&t] ||
-      [self scanChar:FLEXTypeEncodingUnsignedLongLong into:&t] ||
-      [self scanChar:FLEXTypeEncodingFloat into:&t] ||
-      [self scanChar:FLEXTypeEncodingDouble into:&t] ||
-      [self scanChar:FLEXTypeEncodingLongDouble into:&t] ||
-      [self scanChar:FLEXTypeEncodingCBool into:&t] ||
-      [self scanChar:FLEXTypeEncodingCString into:&t] ||
-      [self scanChar:FLEXTypeEncodingSelector into:&t] ||
-      [self scanChar:FLEXTypeEncodingBitField into:&t]) {
-        // Skip optional frame offset
-        [self scanSize];
+    char t = self.nextChar;
+    switch (t) {
+        case FLEXTypeEncodingUnknown:
+        case FLEXTypeEncodingChar:
+        case FLEXTypeEncodingInt:
+        case FLEXTypeEncodingShort:
+        case FLEXTypeEncodingLong:
+        case FLEXTypeEncodingLongLong:
+        case FLEXTypeEncodingUnsignedChar:
+        case FLEXTypeEncodingUnsignedInt:
+        case FLEXTypeEncodingUnsignedShort:
+        case FLEXTypeEncodingUnsignedLong:
+        case FLEXTypeEncodingUnsignedLongLong:
+        case FLEXTypeEncodingFloat:
+        case FLEXTypeEncodingDouble:
+        case FLEXTypeEncodingLongDouble:
+        case FLEXTypeEncodingCBool:
+        case FLEXTypeEncodingCString:
+        case FLEXTypeEncodingSelector:
+        case FLEXTypeEncodingBitField: {
+            self.scan.scanLocation++;
+            // Skip optional frame offset
+            [self scanSize];
+            
+            if (t == FLEXTypeEncodingBitField) {
+                self.scan.scanLocation = start;
+                return -1;
+            } else {
+                // Compute size
+                size = [self sizeForType:t];
+            }
+        }
+            break;
         
         
-        if (t == FLEXTypeEncodingBitField) {
-            self.scan.scanLocation = start;
-            return -1;
-        } else {
-            // Compute size
-            size = [self sizeForType:t];
+        case FLEXTypeEncodingObjcObject:
+        case FLEXTypeEncodingObjcClass: {
+            self.scan.scanLocation++;
+            // These might have numbers OR quotes after them
+            // Skip optional frame offset
+            [self scanSize];
+            [self scanPair:FLEXTypeEncodingQuote close:FLEXTypeEncodingQuote];
+            size = sizeof(id);
         }
         }
-    }
-
-    // These might have numbers OR quotes after them
-    else if ([self scanChar:FLEXTypeEncodingObjcObject] || [self scanChar:FLEXTypeEncodingObjcClass]) {
-        // Skip optional frame offset
-        [self scanSize];
-        [self scanPair:FLEXTypeEncodingQuote close:FLEXTypeEncodingQuote];
-        size = sizeof(id);
+            break;
+            
+        default: break;
     }
     }
 
 
     if (size) {
     if (size) {
@@ -430,8 +455,13 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
 }
 }
 
 
 - (BOOL)canScanString:(NSString *)str {
 - (BOOL)canScanString:(NSString *)str {
-    if ([self scanString:str]) {
-        self.scan.scanLocation -= str.length;
+    NSScanner *scan = self.scan;
+    NSUInteger len = str.length;
+    unichar buff1[len], buff2[len];
+    
+    [str getCharacters:buff1];
+    [scan.string getCharacters:buff2 range:NSMakeRange(scan.scanLocation, len)];
+    if (memcmp(buff1, buff2, len) == 0) {
         return YES;
         return YES;
     }
     }
 
 
@@ -439,15 +469,23 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
 }
 }
 
 
 - (BOOL)canScanChar:(char)c {
 - (BOOL)canScanChar:(char)c {
-    return [self canScanString:S(c)];
+    NSScanner *scan = self.scan;
+    if (scan.scanLocation >= scan.string.length) return NO;
+    
+    return [scan.string characterAtIndex:scan.scanLocation] == c;
 }
 }
 
 
 - (BOOL)scanChar:(char)c {
 - (BOOL)scanChar:(char)c {
-    return [self scanString:S(c)];
+    if ([self canScanChar:c]) {
+        self.scan.scanLocation++;
+        return YES;
+    }
+    
+    return NO;
 }
 }
 
 
 - (BOOL)scanChar:(char)c into:(char *)ref {
 - (BOOL)scanChar:(char)c into:(char *)ref {
-    if ([self scanString:S(c)]) {
+    if ([self scanChar:c]) {
         *ref = c;
         *ref = c;
         return YES;
         return YES;
     }
     }
@@ -546,42 +584,70 @@ BOOL FLEXGetSizeAndAlignment(const char *type, NSUInteger *sizep, NSUInteger *al
             return NO;
             return NO;
         }
         }
     }
     }
+    
+    char next = self.nextChar;
 
 
     // Check for struct/union/array, scan past it
     // Check for struct/union/array, scan past it
-    if ([self scanPair:FLEXTypeEncodingStructBegin close:FLEXTypeEncodingStructEnd] ||
-      [self scanPair:FLEXTypeEncodingUnionBegin close:FLEXTypeEncodingUnionEnd] ||
-      [self scanPair:FLEXTypeEncodingArrayBegin close:FLEXTypeEncodingArrayEnd]) {
-        return YES;
+    FLEXTypeEncoding opening = FLEXTypeEncodingNull, closing = FLEXTypeEncodingNull;
+    BOOL checkPair = YES;
+    switch (next) {
+        case FLEXTypeEncodingStructBegin:
+            opening = FLEXTypeEncodingStructBegin;
+            closing = FLEXTypeEncodingStructEnd;
+            break;
+        case FLEXTypeEncodingUnionBegin:
+            opening = FLEXTypeEncodingUnionBegin;
+            closing = FLEXTypeEncodingUnionEnd;
+            break;
+        case FLEXTypeEncodingArrayBegin:
+            opening = FLEXTypeEncodingArrayBegin;
+            closing = FLEXTypeEncodingArrayEnd;
+            break;
+            
+        default:
+            checkPair = NO;
+            break;
     }
     }
-
-    // Scan single thing and possible size and return
-    if ([self scanChar:FLEXTypeEncodingUnknown] ||
-      [self scanChar:FLEXTypeEncodingChar] ||
-      [self scanChar:FLEXTypeEncodingInt] ||
-      [self scanChar:FLEXTypeEncodingShort] ||
-      [self scanChar:FLEXTypeEncodingLong] ||
-      [self scanChar:FLEXTypeEncodingLongLong] ||
-      [self scanChar:FLEXTypeEncodingUnsignedChar] ||
-      [self scanChar:FLEXTypeEncodingUnsignedInt] ||
-      [self scanChar:FLEXTypeEncodingUnsignedShort] ||
-      [self scanChar:FLEXTypeEncodingUnsignedLong] ||
-      [self scanChar:FLEXTypeEncodingUnsignedLongLong] ||
-      [self scanChar:FLEXTypeEncodingFloat] ||
-      [self scanChar:FLEXTypeEncodingDouble] ||
-      [self scanChar:FLEXTypeEncodingLongDouble] ||
-      [self scanChar:FLEXTypeEncodingCBool] ||
-      [self scanChar:FLEXTypeEncodingCString] ||
-      [self scanChar:FLEXTypeEncodingSelector] ||
-      [self scanChar:FLEXTypeEncodingBitField]) {
-        // Size is optional
-        [self scanSize];
+    
+    if (checkPair && [self scanPair:opening close:closing]) {
         return YES;
         return YES;
     }
     }
 
 
-    // These might have numbers OR quotes after them
-    if ([self scanChar:FLEXTypeEncodingObjcObject] || [self scanChar:FLEXTypeEncodingObjcClass]) {
-        [self scanSize] || [self scanPair:FLEXTypeEncodingQuote close:FLEXTypeEncodingQuote];
-        return YES;
+    // Scan single thing and possible size and return
+    switch (next) {
+        case FLEXTypeEncodingUnknown:
+        case FLEXTypeEncodingChar:
+        case FLEXTypeEncodingInt:
+        case FLEXTypeEncodingShort:
+        case FLEXTypeEncodingLong:
+        case FLEXTypeEncodingLongLong:
+        case FLEXTypeEncodingUnsignedChar:
+        case FLEXTypeEncodingUnsignedInt:
+        case FLEXTypeEncodingUnsignedShort:
+        case FLEXTypeEncodingUnsignedLong:
+        case FLEXTypeEncodingUnsignedLongLong:
+        case FLEXTypeEncodingFloat:
+        case FLEXTypeEncodingDouble:
+        case FLEXTypeEncodingLongDouble:
+        case FLEXTypeEncodingCBool:
+        case FLEXTypeEncodingCString:
+        case FLEXTypeEncodingSelector:
+        case FLEXTypeEncodingBitField: {
+            self.scan.scanLocation++;
+            // Size is optional
+            [self scanSize];
+            return YES;
+        }
+        
+        case FLEXTypeEncodingObjcObject:
+        case FLEXTypeEncodingObjcClass: {
+            self.scan.scanLocation++;
+            // These might have numbers OR quotes after them
+            [self scanSize] || [self scanPair:FLEXTypeEncodingQuote close:FLEXTypeEncodingQuote];
+            return YES;
+        }
+            
+        default: break;
     }
     }
 
 
     self.scan.scanLocation = start;
     self.scan.scanLocation = start;