initial commit
This commit is contained in:
371
Example/Pods/ReactiveObjC/ReactiveObjC/RACSequence.m
generated
Normal file
371
Example/Pods/ReactiveObjC/ReactiveObjC/RACSequence.m
generated
Normal file
@@ -0,0 +1,371 @@
|
||||
//
|
||||
// RACSequence.m
|
||||
// ReactiveObjC
|
||||
//
|
||||
// Created by Justin Spahr-Summers on 2012-10-29.
|
||||
// Copyright (c) 2012 GitHub. All rights reserved.
|
||||
//
|
||||
|
||||
#import "RACSequence.h"
|
||||
#import "RACArraySequence.h"
|
||||
#import "RACDynamicSequence.h"
|
||||
#import "RACEagerSequence.h"
|
||||
#import "RACEmptySequence.h"
|
||||
#import "RACScheduler.h"
|
||||
#import "RACSignal.h"
|
||||
#import "RACSubscriber.h"
|
||||
#import "RACTuple.h"
|
||||
#import "RACUnarySequence.h"
|
||||
|
||||
// An enumerator over sequences.
|
||||
@interface RACSequenceEnumerator : NSEnumerator
|
||||
|
||||
// The sequence the enumerator is enumerating.
|
||||
//
|
||||
// This will change as the enumerator is exhausted. This property should only be
|
||||
// accessed while synchronized on self.
|
||||
@property (nonatomic, strong) RACSequence *sequence;
|
||||
|
||||
@end
|
||||
|
||||
@interface RACSequence ()
|
||||
|
||||
// Performs one iteration of lazy binding, passing through values from `current`
|
||||
// until the sequence is exhausted, then recursively binding the remaining
|
||||
// values in the receiver.
|
||||
//
|
||||
// Returns a new sequence which contains `current`, followed by the combined
|
||||
// result of all applications of `block` to the remaining values in the receiver.
|
||||
- (RACSequence *)bind:(RACSequenceBindBlock)block passingThroughValuesFromSequence:(RACSequence *)current;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RACSequenceEnumerator
|
||||
|
||||
- (id)nextObject {
|
||||
id object = nil;
|
||||
|
||||
@synchronized (self) {
|
||||
object = self.sequence.head;
|
||||
self.sequence = self.sequence.tail;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RACSequence
|
||||
|
||||
#pragma mark Lifecycle
|
||||
|
||||
+ (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence<id> *(^)(void))tailBlock {
|
||||
return [[RACDynamicSequence sequenceWithHeadBlock:headBlock tailBlock:tailBlock] setNameWithFormat:@"+sequenceWithHeadBlock:tailBlock:"];
|
||||
}
|
||||
|
||||
#pragma mark Class cluster primitives
|
||||
|
||||
- (id)head {
|
||||
NSCAssert(NO, @"%s must be overridden by subclasses", __func__);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (RACSequence *)tail {
|
||||
NSCAssert(NO, @"%s must be overridden by subclasses", __func__);
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark RACStream
|
||||
|
||||
+ (RACSequence *)empty {
|
||||
return RACEmptySequence.empty;
|
||||
}
|
||||
|
||||
+ (RACSequence *)return:(id)value {
|
||||
return [RACUnarySequence return:value];
|
||||
}
|
||||
|
||||
- (RACSequence *)bind:(RACSequenceBindBlock (^)(void))block {
|
||||
RACSequenceBindBlock bindBlock = block();
|
||||
return [[self bind:bindBlock passingThroughValuesFromSequence:nil] setNameWithFormat:@"[%@] -bind:", self.name];
|
||||
}
|
||||
|
||||
- (RACSequence *)bind:(RACSequenceBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence {
|
||||
// Store values calculated in the dependency here instead, avoiding any kind
|
||||
// of temporary collection and boxing.
|
||||
//
|
||||
// This relies on the implementation of RACDynamicSequence synchronizing
|
||||
// access to its head, tail, and dependency, and we're only doing it because
|
||||
// we really need the performance.
|
||||
__block RACSequence *valuesSeq = self;
|
||||
__block RACSequence *current = passthroughSequence;
|
||||
__block BOOL stop = NO;
|
||||
|
||||
RACSequence *sequence = [RACDynamicSequence sequenceWithLazyDependency:^ id {
|
||||
while (current.head == nil) {
|
||||
if (stop) return nil;
|
||||
|
||||
// We've exhausted the current sequence, create a sequence from the
|
||||
// next value.
|
||||
id value = valuesSeq.head;
|
||||
|
||||
if (value == nil) {
|
||||
// We've exhausted all the sequences.
|
||||
stop = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
current = (id)bindBlock(value, &stop);
|
||||
if (current == nil) {
|
||||
stop = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
valuesSeq = valuesSeq.tail;
|
||||
}
|
||||
|
||||
NSCAssert([current isKindOfClass:RACSequence.class], @"-bind: block returned an object that is not a sequence: %@", current);
|
||||
return nil;
|
||||
} headBlock:^(id _) {
|
||||
return current.head;
|
||||
} tailBlock:^ id (id _) {
|
||||
if (stop) return nil;
|
||||
|
||||
return [valuesSeq bind:bindBlock passingThroughValuesFromSequence:current.tail];
|
||||
}];
|
||||
|
||||
sequence.name = self.name;
|
||||
return sequence;
|
||||
}
|
||||
|
||||
- (RACSequence *)concat:(RACSequence *)sequence {
|
||||
NSCParameterAssert(sequence != nil);
|
||||
|
||||
return [[[RACArraySequence sequenceWithArray:@[ self, sequence ] offset:0]
|
||||
flatten]
|
||||
setNameWithFormat:@"[%@] -concat: %@", self.name, sequence];
|
||||
}
|
||||
|
||||
- (RACSequence *)zipWith:(RACSequence *)sequence {
|
||||
NSCParameterAssert(sequence != nil);
|
||||
|
||||
return [[RACSequence
|
||||
sequenceWithHeadBlock:^ id {
|
||||
if (self.head == nil || sequence.head == nil) return nil;
|
||||
return RACTuplePack(self.head, sequence.head);
|
||||
} tailBlock:^ id {
|
||||
if (self.tail == nil || [[RACSequence empty] isEqual:self.tail]) return nil;
|
||||
if (sequence.tail == nil || [[RACSequence empty] isEqual:sequence.tail]) return nil;
|
||||
|
||||
return [self.tail zipWith:sequence.tail];
|
||||
}]
|
||||
setNameWithFormat:@"[%@] -zipWith: %@", self.name, sequence];
|
||||
}
|
||||
|
||||
#pragma mark Extended methods
|
||||
|
||||
- (NSArray *)array {
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
for (id obj in self) {
|
||||
[array addObject:obj];
|
||||
}
|
||||
|
||||
return [array copy];
|
||||
}
|
||||
|
||||
- (NSEnumerator *)objectEnumerator {
|
||||
RACSequenceEnumerator *enumerator = [[RACSequenceEnumerator alloc] init];
|
||||
enumerator.sequence = self;
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
- (RACSignal *)signal {
|
||||
return [[self signalWithScheduler:[RACScheduler scheduler]] setNameWithFormat:@"[%@] -signal", self.name];
|
||||
}
|
||||
|
||||
- (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler {
|
||||
return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
|
||||
__block RACSequence *sequence = self;
|
||||
|
||||
return [scheduler scheduleRecursiveBlock:^(void (^reschedule)(void)) {
|
||||
if (sequence.head == nil) {
|
||||
[subscriber sendCompleted];
|
||||
return;
|
||||
}
|
||||
|
||||
[subscriber sendNext:sequence.head];
|
||||
|
||||
sequence = sequence.tail;
|
||||
reschedule();
|
||||
}];
|
||||
}] setNameWithFormat:@"[%@] -signalWithScheduler: %@", self.name, scheduler];
|
||||
}
|
||||
|
||||
- (id)foldLeftWithStart:(id)start reduce:(id (^)(id, id))reduce {
|
||||
NSCParameterAssert(reduce != NULL);
|
||||
|
||||
if (self.head == nil) return start;
|
||||
|
||||
for (id value in self) {
|
||||
start = reduce(start, value);
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
- (id)foldRightWithStart:(id)start reduce:(id (^)(id, RACSequence *))reduce {
|
||||
NSCParameterAssert(reduce != NULL);
|
||||
|
||||
if (self.head == nil) return start;
|
||||
|
||||
RACSequence *rest = [RACSequence sequenceWithHeadBlock:^{
|
||||
if (self.tail) {
|
||||
return [self.tail foldRightWithStart:start reduce:reduce];
|
||||
} else {
|
||||
return start;
|
||||
}
|
||||
} tailBlock:nil];
|
||||
|
||||
return reduce(self.head, rest);
|
||||
}
|
||||
|
||||
- (BOOL)any:(BOOL (^)(id))block {
|
||||
NSCParameterAssert(block != NULL);
|
||||
|
||||
return [self objectPassingTest:block] != nil;
|
||||
}
|
||||
|
||||
- (BOOL)all:(BOOL (^)(id))block {
|
||||
NSCParameterAssert(block != NULL);
|
||||
|
||||
NSNumber *result = [self foldLeftWithStart:@YES reduce:^(NSNumber *accumulator, id value) {
|
||||
return @(accumulator.boolValue && block(value));
|
||||
}];
|
||||
|
||||
return result.boolValue;
|
||||
}
|
||||
|
||||
- (id)objectPassingTest:(BOOL (^)(id))block {
|
||||
NSCParameterAssert(block != NULL);
|
||||
|
||||
return [self filter:block].head;
|
||||
}
|
||||
|
||||
- (RACSequence *)eagerSequence {
|
||||
return [RACEagerSequence sequenceWithArray:self.array offset:0];
|
||||
}
|
||||
|
||||
- (RACSequence *)lazySequence {
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark NSCoding
|
||||
|
||||
- (Class)classForCoder {
|
||||
// Most sequences should be archived as RACArraySequences.
|
||||
return RACArraySequence.class;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)coder {
|
||||
if (![self isKindOfClass:RACArraySequence.class]) return [[RACArraySequence alloc] initWithCoder:coder];
|
||||
|
||||
// Decoding is handled in RACArraySequence.
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder {
|
||||
[coder encodeObject:self.array forKey:@"array"];
|
||||
}
|
||||
|
||||
#pragma mark NSFastEnumeration
|
||||
|
||||
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id *)stackbuf count:(NSUInteger)len {
|
||||
if (state->state == ULONG_MAX) {
|
||||
// Enumeration has completed.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We need to traverse the sequence itself on repeated calls to this
|
||||
// method, so use the 'state' field to track the current head.
|
||||
RACSequence *(^getSequence)(void) = ^{
|
||||
return (__bridge RACSequence *)(void *)state->state;
|
||||
};
|
||||
|
||||
void (^setSequence)(RACSequence *) = ^(RACSequence *sequence) {
|
||||
// Release the old sequence and retain the new one.
|
||||
CFBridgingRelease((void *)state->state);
|
||||
|
||||
state->state = (unsigned long)CFBridgingRetain(sequence);
|
||||
};
|
||||
|
||||
void (^complete)(void) = ^{
|
||||
// Release any stored sequence.
|
||||
setSequence(nil);
|
||||
state->state = ULONG_MAX;
|
||||
};
|
||||
|
||||
if (state->state == 0) {
|
||||
// Since a sequence doesn't mutate, this just needs to be set to
|
||||
// something non-NULL.
|
||||
state->mutationsPtr = state->extra;
|
||||
|
||||
setSequence(self);
|
||||
}
|
||||
|
||||
state->itemsPtr = stackbuf;
|
||||
|
||||
NSUInteger enumeratedCount = 0;
|
||||
while (enumeratedCount < len) {
|
||||
RACSequence *seq = getSequence();
|
||||
|
||||
// Because the objects in a sequence may be generated lazily, we want to
|
||||
// prevent them from being released until the enumerator's used them.
|
||||
__autoreleasing id obj = seq.head;
|
||||
if (obj == nil) {
|
||||
complete();
|
||||
break;
|
||||
}
|
||||
|
||||
stackbuf[enumeratedCount++] = obj;
|
||||
|
||||
if (seq.tail == nil) {
|
||||
complete();
|
||||
break;
|
||||
}
|
||||
|
||||
setSequence(seq.tail);
|
||||
}
|
||||
|
||||
return enumeratedCount;
|
||||
}
|
||||
|
||||
#pragma mark NSObject
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return [self.head hash];
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(RACSequence *)seq {
|
||||
if (self == seq) return YES;
|
||||
if (![seq isKindOfClass:RACSequence.class]) return NO;
|
||||
|
||||
for (id<NSObject> selfObj in self) {
|
||||
id<NSObject> seqObj = seq.head;
|
||||
|
||||
// Handles the nil case too.
|
||||
if (![seqObj isEqual:selfObj]) return NO;
|
||||
|
||||
seq = seq.tail;
|
||||
}
|
||||
|
||||
// self is now depleted -- the argument should be too.
|
||||
return (seq.head == nil);
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user