# HG changeset patch # User Jens Alfke # Date 1206029158 25200 # Node ID e55a17cdabd29568a4e8bc84606f373c83e0d522 # Parent d84d25d6cdbba89cc036fee08038720ddb790133 Configurable logging (LogTo). Added "my_" prefix to category method names. Added MurmurHash. Added UniqueWindowController. Bug fixes. diff -r d84d25d6cdbb -r e55a17cdabd2 Base64.h --- a/Base64.h Sat Mar 08 21:04:41 2008 -0800 +++ b/Base64.h Thu Mar 20 09:05:58 2008 -0700 @@ -9,15 +9,18 @@ #import -@interface NSData (Base64) +//NOTE: Using this requires linking against /usr/lib/libcrypto.dylib. -- (NSString *)base64String; -- (NSString *)base64StringWithNewlines:(BOOL)encodeWithNewlines; -- (NSData *)decodeBase64; -- (NSData *)decodeBase64WithNewLines:(BOOL)encodedWithNewlines; +@interface NSData (MYBase64) -- (NSString *)hexString; -- (NSString *)hexDump; +- (NSString *)my_base64String; +- (NSString *)my_base64StringWithNewlines:(BOOL)encodeWithNewlines; + +- (NSData *)my_decodeBase64; +- (NSData *)my_decodeBase64WithNewLines:(BOOL)encodedWithNewlines; + +- (NSString *)my_hexString; +- (NSString *)my_hexDump; @end diff -r d84d25d6cdbb -r e55a17cdabd2 Base64.m --- a/Base64.m Sat Mar 08 21:04:41 2008 -0800 +++ b/Base64.m Thu Mar 20 09:05:58 2008 -0700 @@ -10,11 +10,13 @@ // #import "Base64.h" + +//NOTE: Using this requires linking against /usr/lib/libcrypto.dylib. #import #import -@implementation NSData (Base64) +@implementation NSData (MYBase64) /** @@ -24,9 +26,9 @@ * Code courtesy of DaveDribin (http://www.dribin.org/dave/) * Taken from http://www.cocoadev.com/index.pl?BaseSixtyFour **/ -- (NSString *)base64String +- (NSString *)my_base64String { - return [self base64StringWithNewlines: YES]; + return [self my_base64StringWithNewlines: YES]; } /** @@ -36,7 +38,7 @@ * Code courtesy of DaveDribin (http://www.dribin.org/dave/) * Taken from http://www.cocoadev.com/index.pl?BaseSixtyFour **/ -- (NSString *)base64StringWithNewlines:(BOOL)encodeWithNewlines +- (NSString *)my_base64StringWithNewlines:(BOOL)encodeWithNewlines { // Create a memory buffer which will contain the Base64 encoded string BIO * mem = BIO_new(BIO_s_mem()); @@ -61,12 +63,12 @@ return base64String; } -- (NSData *)decodeBase64 +- (NSData *)my_decodeBase64 { - return [self decodeBase64WithNewLines:YES]; + return [self my_decodeBase64WithNewLines:YES]; } -- (NSData *)decodeBase64WithNewLines:(BOOL)encodedWithNewlines +- (NSData *)my_decodeBase64WithNewLines:(BOOL)encodedWithNewlines { // Create a memory buffer containing Base64 encoded string data BIO * mem = BIO_new_mem_buf((void *) [self bytes], [self length]); @@ -90,7 +92,7 @@ } -- (NSString *)hexString +- (NSString *)my_hexString { const UInt8 *bytes = self.bytes; NSUInteger length = self.length; @@ -102,7 +104,7 @@ autorelease]; } -- (NSString *)hexDump +- (NSString *)my_hexDump { NSMutableString *ret=[NSMutableString stringWithCapacity:[self length]*2]; /* dumps size bytes of *data to string. Looks like: diff -r d84d25d6cdbb -r e55a17cdabd2 GraphicsUtils.m --- a/GraphicsUtils.m Sat Mar 08 21:04:41 2008 -0800 +++ b/GraphicsUtils.m Thu Mar 20 09:05:58 2008 -0700 @@ -30,7 +30,7 @@ - (NSImage*) my_shrunkToFitIn: (NSSize) maxSize { NSSize size = self.size; - float scale = MIN( size.width/maxSize.width, size.height/maxSize.height ); + float scale = MIN( maxSize.width/size.width, maxSize.height/size.height ); if( scale >= 1.0 ) return self; diff -r d84d25d6cdbb -r e55a17cdabd2 Logging.h --- a/Logging.h Sat Mar 08 21:04:41 2008 -0800 +++ b/Logging.h Thu Mar 20 09:05:58 2008 -0700 @@ -12,12 +12,23 @@ NSString* LOC( NSString *key ); // Localized string lookup -#define Log(FMT,ARGS...) do{if(__builtin_expect(gShouldLog,0)) _Log(FMT,##ARGS);}while(0) +#define Log(FMT,ARGS...) do{if(__builtin_expect(_gShouldLog,0)) _Log(FMT,##ARGS);}while(0) #define Warn Warn void AlwaysLog( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2))); +#define LogTo(DOMAIN,FMT,ARGS...) do{if(__builtin_expect(_gShouldLog,0)) _LogTo(@""#DOMAIN,FMT,##ARGS);}while(0) -extern int gShouldLog; +BOOL _WillLogTo( NSString *domain ); +BOOL EnableLog( BOOL enable ); +#define EnableLogTo( DOMAIN, VALUE ) _EnableLogTo(@""#DOMAIN, VALUE) +#define WillLogTo( DOMAIN ) _WillLogTo(@""#DOMAIN) + + +// internals; don't use directly +extern int _gShouldLog; void _Log( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2))); void Warn( NSString *msg, ... ) __attribute__((format(__NSString__, 1, 2))); +void _LogTo( NSString *domain, NSString *msg, ... ) __attribute__((format(__NSString__, 2, 3))); +BOOL _WillLogTo( NSString *domain ); +BOOL _EnableLogTo( NSString *domain, BOOL enable ); diff -r d84d25d6cdbb -r e55a17cdabd2 Logging.m --- a/Logging.m Sat Mar 08 21:04:41 2008 -0800 +++ b/Logging.m Thu Mar 20 09:05:58 2008 -0700 @@ -23,7 +23,9 @@ } -int gShouldLog = -1; +int _gShouldLog = -1; +static BOOL sConsole; +static NSMutableSet *sEnabledDomains; static BOOL isConsole( int fd ) @@ -37,9 +39,65 @@ } -static void _Logv( NSString *msg, va_list args ) +static void InitLogging() { - if( isConsole(STDERR_FILENO) ) { + if( _gShouldLog != -1 ) + return; + + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + _gShouldLog = NO; + sEnabledDomains = [[NSMutableSet alloc] init]; + NSDictionary *dflts = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]; + for( NSString *key in dflts ) { + if( [key hasPrefix: @"Log"] ) { + BOOL value = [[NSUserDefaults standardUserDefaults] boolForKey: key]; + if( key.length==3 ) + _gShouldLog = value; + else if( value ) + [sEnabledDomains addObject: [key substringFromIndex: 3]]; + } + } + sConsole = isConsole(STDERR_FILENO); + + Log(@"Logging enabled in domains: {%@}", + [[[sEnabledDomains allObjects] sortedArrayUsingSelector: @selector(caseInsensitiveCompare:)] + componentsJoinedByString: @", "]); + [pool drain]; +} + + +BOOL EnableLog( BOOL enable ) +{ + if( _gShouldLog == -1 ) + InitLogging(); + BOOL old = _gShouldLog; + _gShouldLog = enable; + return old; +} + +BOOL _WillLogTo( NSString *domain ) +{ + if( _gShouldLog == -1 ) + InitLogging(); + return _gShouldLog && [sEnabledDomains containsObject: domain]; +} + +BOOL _EnableLogTo( NSString *domain, BOOL enable ) +{ + if( _gShouldLog == -1 ) + InitLogging(); + BOOL old = [sEnabledDomains containsObject: domain]; + if( enable ) + [sEnabledDomains addObject: domain]; + else + [sEnabledDomains removeObject: domain]; + return old; +} + + +static void _Logv( NSString *prefix, NSString *msg, va_list args ) +{ + if( sConsole ) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; static NSDateFormatter *sTimestampFormat; if( ! sTimestampFormat ) { @@ -49,8 +107,10 @@ NSDate *now = [[NSDate alloc] init]; NSString *timestamp = [sTimestampFormat stringFromDate: now]; [now release]; + NSString *separator = prefix.length ?@": " :@""; msg = [[NSString alloc] initWithFormat: msg arguments: args]; - NSString *finalMsg = [[NSString alloc] initWithFormat: @"%@| %@\n", timestamp,msg]; + NSString *finalMsg = [[NSString alloc] initWithFormat: @"%@| %@%@%@\n", + timestamp,prefix,separator,msg]; fputs([finalMsg UTF8String], stderr); [finalMsg release]; [msg release]; @@ -64,32 +124,42 @@ { va_list args; va_start(args,msg); - _Logv(msg,args); + _Logv(@"",msg,args); va_end(args); } void _Log( NSString *msg, ... ) { - if( gShouldLog == -1 ) - gShouldLog = [[NSUserDefaults standardUserDefaults] boolForKey: @"Log"]; - - if( gShouldLog ) { + if( _gShouldLog == -1 ) + InitLogging(); + if( _gShouldLog ) { va_list args; va_start(args,msg); - _Logv(msg,args); + _Logv(@"",msg,args); va_end(args); } } +void _LogTo( NSString *domain, NSString *msg, ... ) +{ + if( _gShouldLog == -1 ) + InitLogging(); + if( _gShouldLog && [sEnabledDomains containsObject: domain] ) { + va_list args; + va_start(args,msg); + _Logv(domain, msg, args); + va_end(args); + } +} + + void Warn( NSString *msg, ... ) { - msg = [@"WARNING*** " stringByAppendingString: msg]; - va_list args; va_start(args,msg); - _Logv(msg,args); + _Logv(@"WARNING*** ",msg,args); va_end(args); } diff -r d84d25d6cdbb -r e55a17cdabd2 MurmurHash.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MurmurHash.c Thu Mar 20 09:05:58 2008 -0700 @@ -0,0 +1,80 @@ +/* + * MurmurHash.c + * MYUtilities + * + * This file created by Jens Alfke on 3/17/08. + * Algorithm & source code by Austin Appleby, released to public domain. + * + * Downloaded 3/16/2008. + * Modified slightly by Jens Alfke (use standard uint32_t and size_t types; + * change 'm' and 'r' to #defines for better C compatibility.) + * + */ + +#include "MurmurHash.h" + + +//----------------------------------------------------------------------------- +// MurmurHash2, by Austin Appleby + +// Note - This code makes a few assumptions about how your machine behaves - + +// 1. We can read a 4-byte value from any address without crashing +// 2. sizeof(int) == 4 **Jens: I fixed this by changing 'unsigned int' to 'uint32_t'** + +// And it has a few limitations - + +// 1. It will not work incrementally. +// 2. It will not produce the same results on little-endian and big-endian +// machines. + +uint32_t MurmurHash2 ( const void * key, size_t len, uint32_t seed ) +{ + // 'm' and 'r' are mixing constants generated offline. + // They're not really 'magic', they just happen to work well. + + #define m 0x5bd1e995 + #define r 24 + + // Initialize the hash to a 'random' value + + uint32_t h = seed ^ len; + + // Mix 4 bytes at a time into the hash + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + uint32_t k = *(uint32_t *)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + // Handle the last few bytes of the input array + + switch(len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} diff -r d84d25d6cdbb -r e55a17cdabd2 MurmurHash.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MurmurHash.h Thu Mar 20 09:05:58 2008 -0700 @@ -0,0 +1,23 @@ +/* + * MurmurHash.h + * MYUtilities + * + * This file created by Jens Alfke on 3/17/08. + * Algorithm & source code by Austin Appleby, released to public domain. + * + * + */ + +#include +#include + +/** An extremely efficient general-purpose hash function. + Murmurhash is claimed to be more than twice as fast as the nearest competitor, + and to offer better-distributed output with fewer collisions. + It is, however not suitable for cryptographic use. + Hash values will differ between bit- and little-endian CPUs, so they shouldn't + be stored persistently or transmitted over the network. + + Written by Austin Appleby: */ + +uint32_t MurmurHash2 ( const void * key, size_t len, uint32_t seed ); diff -r d84d25d6cdbb -r e55a17cdabd2 Target.m --- a/Target.m Sat Mar 08 21:04:41 2008 -0800 +++ b/Target.m Thu Mar 20 09:05:58 2008 -0700 @@ -28,26 +28,30 @@ id $calltarget( NSInvocation *target, id param ) { + id result = nil; if( target && target.target ) { - [target setArgument: ¶m atIndex: 2]; - [target invoke]; - - NSMethodSignature *sig = target.methodSignature; - NSUInteger returnLength = sig.methodReturnLength; - if( returnLength==0 ) - return nil; // void - else { - const char *returnType = sig.methodReturnType; - if( returnType[0]=='@' ) { - id returnObject; - [target getReturnValue: &returnObject]; - return returnObject; + [target retain]; + @try{ + [target setArgument: ¶m atIndex: 2]; + [target invoke]; + + NSMethodSignature *sig = target.methodSignature; + NSUInteger returnLength = sig.methodReturnLength; + if( returnLength==0 ) { + result = nil; // void } else { - UInt8 returnBuffer[returnLength]; - [target getReturnValue: &returnBuffer]; - return [NSValue valueWithBytes: &returnBuffer objCType: returnType]; + const char *returnType = sig.methodReturnType; + if( returnType[0]=='@' ) { + [target getReturnValue: &result]; + } else { + UInt8 returnBuffer[returnLength]; + [target getReturnValue: &returnBuffer]; + result = [NSValue valueWithBytes: &returnBuffer objCType: returnType]; + } } + }@finally{ + [target release]; } - } else - return nil; + } + return result; } diff -r d84d25d6cdbb -r e55a17cdabd2 Test.h --- a/Test.h Sat Mar 08 21:04:41 2008 -0800 +++ b/Test.h Thu Mar 20 09:05:58 2008 -0700 @@ -17,8 +17,10 @@ To run only tests without starting the main program, add the argument "Test_Only". */ #if DEBUG void RunTestCases( int argc, const char **argv ); +extern BOOL gRunningTestCase; #else #define RunTestCases(ARGC,ARGV) +#define gRunningTestCase NO #endif /** The TestCase() macro declares a test case. diff -r d84d25d6cdbb -r e55a17cdabd2 Test.m --- a/Test.m Sat Mar 08 21:04:41 2008 -0800 +++ b/Test.m Thu Mar 20 09:05:58 2008 -0700 @@ -11,11 +11,15 @@ #if DEBUG +BOOL gRunningTestCase; + struct TestCaseLink *gAllTestCases; static int sPassed, sFailed; static BOOL RunTestCase( struct TestCaseLink *test ) { + BOOL oldLogging = EnableLog(YES); + gRunningTestCase = YES; if( test->testptr ) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; Log(@"=== Testing %s ...",test->name); @@ -37,6 +41,8 @@ test->testptr = NULL; // prevents test from being run again } } + gRunningTestCase = NO; + EnableLog(oldLogging); return test->passed; } @@ -63,7 +69,6 @@ void RunTestCases( int argc, const char **argv ) { - gShouldLog = YES; sPassed = sFailed = 0; BOOL stopAfterTests = NO; for( int i=1; i + + +@interface UniqueWindowController : NSWindowController + ++ (UniqueWindowController*) instanceWith: (id)model; ++ (UniqueWindowController*) openWith: (id)model; + +@end + + +@interface UniqueWindowController (Abstract) + +- (id) initWith: (id)model; +@property (readonly) id model; + +@end \ No newline at end of file diff -r d84d25d6cdbb -r e55a17cdabd2 UniqueWindowController.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/UniqueWindowController.m Thu Mar 20 09:05:58 2008 -0700 @@ -0,0 +1,47 @@ +// +// UniqueWindowController.m +// Cloudy +// +// Created by Jens Alfke on 3/14/08. +// Copyright 2008 __MyCompanyName__. All rights reserved. +// + +#import "UniqueWindowController.h" + + +@implementation UniqueWindowController + + ++ (UniqueWindowController*) instanceWith: (id)model +{ + for( NSWindow *window in [NSApp windows] ) { + id delegate = window.delegate; + if( window.isVisible && [delegate isKindOfClass: [self class]] ) { + UniqueWindowController *c = delegate; + if( c.model == model ) + return c; + } + } + return nil; +} + + ++ (UniqueWindowController*) openWith: (id)model +{ + UniqueWindowController *w = [self instanceWith: model]; + if( ! w ) { + w = [[self alloc] initWith: model]; + [w showWindow: self]; + } + [w.window makeKeyAndOrderFront: self]; + return w; +} + + +- (void) windowWillClose: (NSNotification*)n +{ + [self autorelease]; +} + + +@end