// gcc -framework Foundation -O3 -g -o dictfind4 dictfind4.m #import @interface Dict : NSObject { NSArray *_wordPairs; } - (NSArray *)find:(NSString *)toFind; @end @implementation Dict static NSInteger CaseInsensitiveCompare(id a, id b) { return [a compare:b options:NSCaseInsensitiveSearch]; } static NSInteger CaseInsensitiveComparePairs(id a, id b, void *ctx) { return CaseInsensitiveCompare([a objectAtIndex:0], [b objectAtIndex:0]); } - (id)init { if((self = [super init])) { NSString *str = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"]; NSArray *words = [str componentsSeparatedByString:@"\n"]; NSMutableArray *pairs = [NSMutableArray array]; for(NSString *word in words) { NSUInteger length = [word length]; NSUInteger index; for(index = 0; index < length; index++) { NSArray *pair = [NSArray arrayWithObjects: [word substringFromIndex:index], word, nil]; [pairs addObject:pair]; } } _wordPairs = [[pairs sortedArrayUsingFunction:CaseInsensitiveComparePairs context:NULL] copy]; } return self; } - (void)dealloc { [_wordPairs release]; [super dealloc]; } static CFComparisonResult FindComparator(const void *a, const void *b, void *ctx) { id aobj = (id)a; id bobj = (id)b; if([aobj isKindOfClass:[NSArray class]]) aobj = [aobj objectAtIndex:0]; if([bobj isKindOfClass:[NSArray class]]) bobj = [bobj objectAtIndex:0]; NSInteger result = CaseInsensitiveCompare(aobj, bobj); if(result == NSOrderedSame) // force the search to the beginning of any matches return NSOrderedAscending; return result; } - (NSArray *)find:(NSString *)toFind { NSUInteger pairsCount = [_wordPairs count]; NSUInteger index = CFArrayBSearchValues((CFArrayRef)_wordPairs, CFRangeMake(0, pairsCount), toFind, FindComparator, NULL); NSMutableArray *array = [NSMutableArray array]; for(; index < pairsCount; index++) { NSString *word = [[_wordPairs objectAtIndex:index] objectAtIndex:1]; if([word rangeOfString:toFind options:NSCaseInsensitiveSearch].location != NSNotFound) [array addObject:word]; else break; } return array; } @end int main(int argc, char **argv) { NSAutoreleasePool *outerPool = [[NSAutoreleasePool alloc] init]; NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init]; NSLog(@"Initializing dictionary..."); Dict *dict = [[Dict alloc] init]; NSLog(@"Done initializing, starting run"); [innerPool release]; NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate]; NSTimeInterval lastPrinted = start; unsigned counter = 0; while(1) { innerPool = [[NSAutoreleasePool alloc] init]; [dict find:@"bob"]; counter++; NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; if(now - lastPrinted >= 1.0) { NSLog(@"%.1f/sec", counter / (now - start)); lastPrinted = now; } [innerPool release]; } [dict release]; [outerPool release]; return 0; }