RACSequence.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //
  2. // RACSequence.m
  3. // ReactiveObjC
  4. //
  5. // Created by Justin Spahr-Summers on 2012-10-29.
  6. // Copyright (c) 2012 GitHub. All rights reserved.
  7. //
  8. #import "RACSequence.h"
  9. #import "RACArraySequence.h"
  10. #import "RACDynamicSequence.h"
  11. #import "RACEagerSequence.h"
  12. #import "RACEmptySequence.h"
  13. #import "RACScheduler.h"
  14. #import "RACSignal.h"
  15. #import "RACSubscriber.h"
  16. #import "RACTuple.h"
  17. #import "RACUnarySequence.h"
  18. // An enumerator over sequences.
  19. @interface RACSequenceEnumerator : NSEnumerator
  20. // The sequence the enumerator is enumerating.
  21. //
  22. // This will change as the enumerator is exhausted. This property should only be
  23. // accessed while synchronized on self.
  24. @property (nonatomic, strong) RACSequence *sequence;
  25. @end
  26. @interface RACSequence ()
  27. // Performs one iteration of lazy binding, passing through values from `current`
  28. // until the sequence is exhausted, then recursively binding the remaining
  29. // values in the receiver.
  30. //
  31. // Returns a new sequence which contains `current`, followed by the combined
  32. // result of all applications of `block` to the remaining values in the receiver.
  33. - (RACSequence *)bind:(RACSequenceBindBlock)block passingThroughValuesFromSequence:(RACSequence *)current;
  34. @end
  35. @implementation RACSequenceEnumerator
  36. - (id)nextObject {
  37. id object = nil;
  38. @synchronized (self) {
  39. object = self.sequence.head;
  40. self.sequence = self.sequence.tail;
  41. }
  42. return object;
  43. }
  44. @end
  45. @implementation RACSequence
  46. #pragma mark Lifecycle
  47. + (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence<id> *(^)(void))tailBlock {
  48. return [[RACDynamicSequence sequenceWithHeadBlock:headBlock tailBlock:tailBlock] setNameWithFormat:@"+sequenceWithHeadBlock:tailBlock:"];
  49. }
  50. #pragma mark Class cluster primitives
  51. - (id)head {
  52. NSCAssert(NO, @"%s must be overridden by subclasses", __func__);
  53. return nil;
  54. }
  55. - (RACSequence *)tail {
  56. NSCAssert(NO, @"%s must be overridden by subclasses", __func__);
  57. return nil;
  58. }
  59. #pragma mark RACStream
  60. + (RACSequence *)empty {
  61. return RACEmptySequence.empty;
  62. }
  63. + (RACSequence *)return:(id)value {
  64. return [RACUnarySequence return:value];
  65. }
  66. - (RACSequence *)bind:(RACSequenceBindBlock (^)(void))block {
  67. RACSequenceBindBlock bindBlock = block();
  68. return [[self bind:bindBlock passingThroughValuesFromSequence:nil] setNameWithFormat:@"[%@] -bind:", self.name];
  69. }
  70. - (RACSequence *)bind:(RACSequenceBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence {
  71. // Store values calculated in the dependency here instead, avoiding any kind
  72. // of temporary collection and boxing.
  73. //
  74. // This relies on the implementation of RACDynamicSequence synchronizing
  75. // access to its head, tail, and dependency, and we're only doing it because
  76. // we really need the performance.
  77. __block RACSequence *valuesSeq = self;
  78. __block RACSequence *current = passthroughSequence;
  79. __block BOOL stop = NO;
  80. RACSequence *sequence = [RACDynamicSequence sequenceWithLazyDependency:^ id {
  81. while (current.head == nil) {
  82. if (stop) return nil;
  83. // We've exhausted the current sequence, create a sequence from the
  84. // next value.
  85. id value = valuesSeq.head;
  86. if (value == nil) {
  87. // We've exhausted all the sequences.
  88. stop = YES;
  89. return nil;
  90. }
  91. current = (id)bindBlock(value, &stop);
  92. if (current == nil) {
  93. stop = YES;
  94. return nil;
  95. }
  96. valuesSeq = valuesSeq.tail;
  97. }
  98. NSCAssert([current isKindOfClass:RACSequence.class], @"-bind: block returned an object that is not a sequence: %@", current);
  99. return nil;
  100. } headBlock:^(id _) {
  101. return current.head;
  102. } tailBlock:^ id (id _) {
  103. if (stop) return nil;
  104. return [valuesSeq bind:bindBlock passingThroughValuesFromSequence:current.tail];
  105. }];
  106. sequence.name = self.name;
  107. return sequence;
  108. }
  109. - (RACSequence *)concat:(RACSequence *)sequence {
  110. NSCParameterAssert(sequence != nil);
  111. return [[[RACArraySequence sequenceWithArray:@[ self, sequence ] offset:0]
  112. flatten]
  113. setNameWithFormat:@"[%@] -concat: %@", self.name, sequence];
  114. }
  115. - (RACSequence *)zipWith:(RACSequence *)sequence {
  116. NSCParameterAssert(sequence != nil);
  117. return [[RACSequence
  118. sequenceWithHeadBlock:^ id {
  119. if (self.head == nil || sequence.head == nil) return nil;
  120. return RACTuplePack(self.head, sequence.head);
  121. } tailBlock:^ id {
  122. if (self.tail == nil || [[RACSequence empty] isEqual:self.tail]) return nil;
  123. if (sequence.tail == nil || [[RACSequence empty] isEqual:sequence.tail]) return nil;
  124. return [self.tail zipWith:sequence.tail];
  125. }]
  126. setNameWithFormat:@"[%@] -zipWith: %@", self.name, sequence];
  127. }
  128. #pragma mark Extended methods
  129. - (NSArray *)array {
  130. NSMutableArray *array = [NSMutableArray array];
  131. for (id obj in self) {
  132. [array addObject:obj];
  133. }
  134. return [array copy];
  135. }
  136. - (NSEnumerator *)objectEnumerator {
  137. RACSequenceEnumerator *enumerator = [[RACSequenceEnumerator alloc] init];
  138. enumerator.sequence = self;
  139. return enumerator;
  140. }
  141. - (RACSignal *)signal {
  142. return [[self signalWithScheduler:[RACScheduler scheduler]] setNameWithFormat:@"[%@] -signal", self.name];
  143. }
  144. - (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler {
  145. return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
  146. __block RACSequence *sequence = self;
  147. return [scheduler scheduleRecursiveBlock:^(void (^reschedule)(void)) {
  148. if (sequence.head == nil) {
  149. [subscriber sendCompleted];
  150. return;
  151. }
  152. [subscriber sendNext:sequence.head];
  153. sequence = sequence.tail;
  154. reschedule();
  155. }];
  156. }] setNameWithFormat:@"[%@] -signalWithScheduler: %@", self.name, scheduler];
  157. }
  158. - (id)foldLeftWithStart:(id)start reduce:(id (^)(id, id))reduce {
  159. NSCParameterAssert(reduce != NULL);
  160. if (self.head == nil) return start;
  161. for (id value in self) {
  162. start = reduce(start, value);
  163. }
  164. return start;
  165. }
  166. - (id)foldRightWithStart:(id)start reduce:(id (^)(id, RACSequence *))reduce {
  167. NSCParameterAssert(reduce != NULL);
  168. if (self.head == nil) return start;
  169. RACSequence *rest = [RACSequence sequenceWithHeadBlock:^{
  170. if (self.tail) {
  171. return [self.tail foldRightWithStart:start reduce:reduce];
  172. } else {
  173. return start;
  174. }
  175. } tailBlock:nil];
  176. return reduce(self.head, rest);
  177. }
  178. - (BOOL)any:(BOOL (^)(id))block {
  179. NSCParameterAssert(block != NULL);
  180. return [self objectPassingTest:block] != nil;
  181. }
  182. - (BOOL)all:(BOOL (^)(id))block {
  183. NSCParameterAssert(block != NULL);
  184. NSNumber *result = [self foldLeftWithStart:@YES reduce:^(NSNumber *accumulator, id value) {
  185. return @(accumulator.boolValue && block(value));
  186. }];
  187. return result.boolValue;
  188. }
  189. - (id)objectPassingTest:(BOOL (^)(id))block {
  190. NSCParameterAssert(block != NULL);
  191. return [self filter:block].head;
  192. }
  193. - (RACSequence *)eagerSequence {
  194. return [RACEagerSequence sequenceWithArray:self.array offset:0];
  195. }
  196. - (RACSequence *)lazySequence {
  197. return self;
  198. }
  199. #pragma mark NSCopying
  200. - (id)copyWithZone:(NSZone *)zone {
  201. return self;
  202. }
  203. #pragma mark NSCoding
  204. - (Class)classForCoder {
  205. // Most sequences should be archived as RACArraySequences.
  206. return RACArraySequence.class;
  207. }
  208. - (id)initWithCoder:(NSCoder *)coder {
  209. if (![self isKindOfClass:RACArraySequence.class]) return [[RACArraySequence alloc] initWithCoder:coder];
  210. // Decoding is handled in RACArraySequence.
  211. return [super init];
  212. }
  213. - (void)encodeWithCoder:(NSCoder *)coder {
  214. [coder encodeObject:self.array forKey:@"array"];
  215. }
  216. #pragma mark NSFastEnumeration
  217. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(__unsafe_unretained id *)stackbuf count:(NSUInteger)len {
  218. if (state->state == ULONG_MAX) {
  219. // Enumeration has completed.
  220. return 0;
  221. }
  222. // We need to traverse the sequence itself on repeated calls to this
  223. // method, so use the 'state' field to track the current head.
  224. RACSequence *(^getSequence)(void) = ^{
  225. return (__bridge RACSequence *)(void *)state->state;
  226. };
  227. void (^setSequence)(RACSequence *) = ^(RACSequence *sequence) {
  228. // Release the old sequence and retain the new one.
  229. CFBridgingRelease((void *)state->state);
  230. state->state = (unsigned long)CFBridgingRetain(sequence);
  231. };
  232. void (^complete)(void) = ^{
  233. // Release any stored sequence.
  234. setSequence(nil);
  235. state->state = ULONG_MAX;
  236. };
  237. if (state->state == 0) {
  238. // Since a sequence doesn't mutate, this just needs to be set to
  239. // something non-NULL.
  240. state->mutationsPtr = state->extra;
  241. setSequence(self);
  242. }
  243. state->itemsPtr = stackbuf;
  244. NSUInteger enumeratedCount = 0;
  245. while (enumeratedCount < len) {
  246. RACSequence *seq = getSequence();
  247. // Because the objects in a sequence may be generated lazily, we want to
  248. // prevent them from being released until the enumerator's used them.
  249. __autoreleasing id obj = seq.head;
  250. if (obj == nil) {
  251. complete();
  252. break;
  253. }
  254. stackbuf[enumeratedCount++] = obj;
  255. if (seq.tail == nil) {
  256. complete();
  257. break;
  258. }
  259. setSequence(seq.tail);
  260. }
  261. return enumeratedCount;
  262. }
  263. #pragma mark NSObject
  264. - (NSUInteger)hash {
  265. return [self.head hash];
  266. }
  267. - (BOOL)isEqual:(RACSequence *)seq {
  268. if (self == seq) return YES;
  269. if (![seq isKindOfClass:RACSequence.class]) return NO;
  270. for (id<NSObject> selfObj in self) {
  271. id<NSObject> seqObj = seq.head;
  272. // Handles the nil case too.
  273. if (![seqObj isEqual:selfObj]) return NO;
  274. seq = seq.tail;
  275. }
  276. // self is now depleted -- the argument should be too.
  277. return (seq.head == nil);
  278. }
  279. @end