Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
The TOCCancelTokenAndSource.m file from https://github.com/Strilanc/ObjC-CollapsingFutures, stripped of details related to the implementation of whenCancelledDo:unless:. Clone collapsing futures, paste this gist over TOCCancelTokenAndSource.m, and try to get the tests passing again. (Note that the tests aren't testing for thread safety. You may …
#import "TOCCancelTokenAndSource.h"
#import "TOCFutureAndSource.h"
#import "TOCInternal.h"
#include <libkern/OSAtomic.h>
static TOCCancelToken* SharedCancelledToken = nil;
static TOCCancelToken* SharedImmortalToken = nil;
@implementation TOCCancelToken {
@private NSMutableArray* _cancelHandlers;
@private enum TOCCancelTokenState _state;
}
+(void) initialize {
SharedCancelledToken = [TOCCancelToken new];
SharedCancelledToken->_state = TOCCancelTokenState_Cancelled;
SharedImmortalToken = [TOCCancelToken new];
assert(SharedImmortalToken->_state == TOCCancelTokenState_Immortal); // default state should be immortal
}
+(TOCCancelToken *)cancelledToken {
return SharedCancelledToken;
}
+(TOCCancelToken *)immortalToken {
return SharedImmortalToken;
}
+(TOCCancelToken*) _ForSource_cancellableToken {
TOCCancelToken* token = [TOCCancelToken new];
token->_cancelHandlers = [NSMutableArray array];
token->_state = TOCCancelTokenState_StillCancellable;
return token;
}
-(bool) _ForSource_tryImmortalize {
@synchronized(self) {
if (_state != TOCCancelTokenState_StillCancellable) return false;
_state = TOCCancelTokenState_Immortal;
_cancelHandlers = nil;
}
return true;
}
-(bool) _ForSource_tryCancel {
NSArray* cancelHandlersSnapshot;
@synchronized(self) {
if (_state != TOCCancelTokenState_StillCancellable) return false;
_state = TOCCancelTokenState_Cancelled;
cancelHandlersSnapshot = _cancelHandlers;
_cancelHandlers = nil;
}
for (TOCCancelHandler handler in cancelHandlersSnapshot) {
handler();
}
return true;
}
-(enum TOCCancelTokenState)state {
@synchronized(self) {
return _state;
}
}
-(bool)isAlreadyCancelled {
return self.state == TOCCancelTokenState_Cancelled;
}
-(bool)canStillBeCancelled {
return self.state == TOCCancelTokenState_StillCancellable;
}
-(void)whenCancelledDo:(TOCCancelHandler)cancelHandler {
require(cancelHandler != nil);
@synchronized(self) {
if (_state == TOCCancelTokenState_Immortal) return;
if (_state == TOCCancelTokenState_StillCancellable) {
[_cancelHandlers addObject:cancelHandler];
return;
}
}
cancelHandler();
}
-(void) whenCancelledDo:(TOCCancelHandler)cancelHandler
unless:(TOCCancelToken*)unlessCancelledToken {
require(cancelHandler != nil);
// go for it!
}
-(NSString*) description {
switch (self.state) {
case TOCCancelTokenState_Cancelled:
return @"Cancelled Token";
case TOCCancelTokenState_Immortal:
return @"Uncancelled Token (Immortal)";
case TOCCancelTokenState_StillCancellable:
return @"Uncancelled Token";
default:
return @"Cancel token in an unrecognized state";
}
}
@end
@implementation TOCCancelTokenSource
@synthesize token;
-(TOCCancelTokenSource*) init {
self = [super init];
if (self) {
self->token = [TOCCancelToken _ForSource_cancellableToken];
}
return self;
}
+(TOCCancelTokenSource*) cancelTokenSourceUntil:(TOCCancelToken*)untilCancelledToken {
TOCCancelTokenSource* source = [TOCCancelTokenSource new];
[untilCancelledToken whenCancelledDo:^{ [source cancel]; }
unless:source.token];
return source;
}
-(void) dealloc {
[token _ForSource_tryImmortalize];
}
-(void) cancel {
[self tryCancel];
}
-(bool)tryCancel {
return [token _ForSource_tryCancel];
}
-(NSString*) description {
return [NSString stringWithFormat:@"Cancel Token Source: %@", token];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment