idb/FBControlCore/Utility/FBConcurrentCollectionOpera...

125 строки
3.2 KiB
Objective-C

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "FBConcurrentCollectionOperations.h"
@interface FBConcurrentCollectionOperations_FilterTerminal : NSObject
+ (instancetype)terminal;
@end
@implementation FBConcurrentCollectionOperations_FilterTerminal
+ (instancetype)terminal
{
static dispatch_once_t onceToken;
static FBConcurrentCollectionOperations_FilterTerminal *terminal;
dispatch_once(&onceToken, ^{
terminal = [FBConcurrentCollectionOperations_FilterTerminal new];
});
return terminal;
}
@end
@implementation FBConcurrentCollectionOperations
#pragma mark Public
+ (NSArray *)generate:(NSUInteger)count withBlock:( id(^)(NSUInteger index) )block
{
NSMutableArray *array = [NSMutableArray array];
for (NSUInteger index = 0; index < count; index++) {
[array addObject:NSNull.null];
}
dispatch_apply((size_t) count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ (size_t iteration) {
id object = block(iteration);
if (object) {
@synchronized(array) {
array[iteration] = object;
}
}
});
return [array copy];
}
+ (NSArray *)map:(NSArray *)array withBlock:( id(^)(id object) )block
{
return [self
generate:array.count
withBlock:^ id (NSUInteger index) {
return block(array[index]);
}];
}
+ (NSArray *)filter:(NSArray *)array predicate:(NSPredicate *)predicate
{
return [self filterMap:array predicate:predicate map:^ id (id object) {
return object;
}];
}
+ (NSArray *)mapFilter:(NSArray *)array map:(id (^)(id))block predicate:(NSPredicate *)predicate
{
NSMutableArray *output = [NSMutableArray array];
for (NSUInteger index = 0; index < array.count; index++) {
[output addObject:NSNull.null];
}
dispatch_apply(array.count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ (size_t iteration) {
id object = block(array[iteration]);
BOOL pass = [predicate evaluateWithObject:object];
if (!pass) {
object = FBConcurrentCollectionOperations_FilterTerminal.terminal;
}
else if (!object) {
object = NSNull.null;
}
@synchronized(output) {
output[iteration] = object;
}
});
return [output filteredArrayUsingPredicate:self.nonTerminalPredicate];
}
+ (NSArray *)filterMap:(NSArray *)array predicate:(NSPredicate *)predicate map:(id (^)(id))block
{
return [[self
map:array
withBlock:^ id (id object) {
BOOL pass = [predicate evaluateWithObject:object];
if (!pass) {
return FBConcurrentCollectionOperations_FilterTerminal.terminal;
}
object = block(object);
if (!object) {
return NSNull.null;
}
return object;
}]
filteredArrayUsingPredicate:self.nonTerminalPredicate];
}
#pragma mark Private
+ (NSPredicate *)nonTerminalPredicate
{
static dispatch_once_t onceToken;
static NSPredicate *predicate;
dispatch_once(&onceToken, ^{
predicate = [NSPredicate predicateWithBlock:^ BOOL (id evaluatedObject, NSDictionary *_) {
return evaluatedObject != FBConcurrentCollectionOperations_FilterTerminal.terminal;
}];
});
return predicate;
}
@end