/* * Grouch.app Copyright (C) 2006 Andy Sveikauskas * ------------------------------------------------------------------------ * This program is free software under the GNU General Public License * -- * See note at GrouchTimedDictionary.h. */ #import #import #import #import #include @protocol GrouchTimedDictKeepCompilerHappy - (BOOL)mayRelease; @end // Wrapper for objects in dictionary. // Each value has a time tag attached. @interface GrouchTimedDictObjectWrapper : NSObject { @public GrouchTimedDictionary *dict; time_t createdTime; NSObject *originalObject; } + wrapperWithObject:obj forDict:dict; - initWithObject:obj forDict:dict; - (void)dealloc; - (BOOL)shouldRemove:(time_t)cmp; @end @implementation GrouchTimedDictObjectWrapper + wrapperWithObject:obj forDict:d { return [[[self new] initWithObject:obj forDict:d] autorelease]; } - initWithObject:obj forDict:d { [originalObject=obj retain]; dict = d; time(&createdTime); return self; } - (void)dealloc { NSObject *t; SEL sel; if( dict && (t=[dict target]) && (sel=[dict action]) ) [t performSelector:sel withObject:originalObject]; [originalObject release]; [super dealloc]; } - (BOOL)shouldRemove:(time_t)cmp { id obj = (id)originalObject; return [dict expireTime] && (createdTime <= cmp) && (![originalObject respondsToSelector:@selector(mayRelease)] || [obj mayRelease]); } @end @interface GrouchTimedDictEnumerator : NSEnumerator { NSEnumerator *objects; } + enumWithDict:(NSMutableDictionary*)d; - initWithDict:(NSMutableDictionary*)d; - nextObject; @end @implementation GrouchTimedDictEnumerator + enumWithDict:(NSMutableDictionary*)d { return [[self alloc] initWithDict:d]; } - initWithDict:(NSMutableDictionary*)d { objects = [d objectEnumerator]; return self; } - nextObject { GrouchTimedDictObjectWrapper *r = [objects nextObject]; if( r ) return r->originalObject; else return r; } @end @implementation GrouchTimedDictionary - init { dict = [NSMutableDictionary new]; return self; } - (void)dealloc { NSEnumerator *e = [dict objectEnumerator]; GrouchTimedDictObjectWrapper *obj; while( (obj=[e nextObject]) ) obj->dict = nil; [dict release]; [super dealloc]; } - (void)expireObjects { if( expireTime ) { time_t now; NSEnumerator *keys, *objects; NSMutableArray *badKeys = [NSMutableArray new]; id key; int i; time( &now ); now -= expireTime; keys = [dict keyEnumerator]; objects = [dict objectEnumerator]; while( (key=[keys nextObject]) ) { GrouchTimedDictObjectWrapper *r = [objects nextObject]; if( [r shouldRemove:now] ) [badKeys addObject:key]; } for( i=0; i<[badKeys count]; ++i ) { key = [badKeys objectAtIndex:i]; NS_DURING [dict removeObjectForKey:key]; NS_HANDLER [badKeys release]; [localException raise]; NS_ENDHANDLER } [badKeys release]; } } - (unsigned int)expireTime { return expireTime; } - (void)expireTime:(unsigned int)n { expireTime = n; } - target { return target; } - (void)setTarget:t { target = t; } - (SEL)action { return action; } - (void)setAction:(SEL)a { action = a; } - (unsigned)count { return [dict count]; } // NSDictionary primitives - initWithObjects:(id*)objs forKeys:(id*)keys count:(unsigned)count { if( dict ) [dict release]; dict = [[NSMutableDictionary alloc] initWithObjects:objs forKeys:keys count:count]; return self; } - (NSEnumerator*)keyEnumerator { return [dict keyEnumerator]; } - (NSEnumerator*)objectEnumerator { return [GrouchTimedDictEnumerator enumWithDict:dict]; } - objectForKey:k { GrouchTimedDictObjectWrapper *r = [dict objectForKey:k]; if( r ) return r->originalObject; else return r; } // NSMutableDictionary primitives - initWithCapacity:(unsigned)capacity { if( dict ) [dict release]; dict = [[NSMutableDictionary alloc] initWithCapacity:capacity]; return self; } - (void)removeObjectForKey:key { [dict removeObjectForKey:key]; } - (void)setObject:obj forKey:k { [dict setObject:[GrouchTimedDictObjectWrapper wrapperWithObject:obj forDict:self] forKey:k]; } @end