#include #import "REAOperatorNode.h" #import "REANodesManager.h" typedef id (^REAOperatorBlock)(NSArray *inputNodes); #define REA_REDUCE(OP) ^(NSArray *inputNodes) { \ double acc = [[inputNodes[0] value] doubleValue]; \ for (NSUInteger i = 1; i < inputNodes.count; i++) { \ double a = acc, b = [[inputNodes[i] value] doubleValue]; \ acc = OP; \ } \ return @(acc); \ } #define REA_SINGLE(OP) ^(NSArray *inputNodes) { \ double a = [[inputNodes[0] value] doubleValue]; \ return @(OP); \ } #define REA_INFIX(OP) ^(NSArray *inputNodes) { \ double a = [[inputNodes[0] value] doubleValue]; \ double b = [[inputNodes[1] value] doubleValue]; \ return @(OP); \ } @implementation REAOperatorNode { NSArray *_input; NSMutableArray *_inputNodes; REAOperatorBlock _op; } - (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary *)config { static NSDictionary *OPS; static dispatch_once_t opsToken; dispatch_once(&opsToken, ^{ OPS = @{ // arithmetic @"add": REA_REDUCE(a + b), @"sub": REA_REDUCE(a - b), @"multiply": REA_REDUCE(a * b), @"divide": REA_REDUCE(a / b), @"pow": REA_REDUCE(pow(a, b)), @"modulo": REA_REDUCE(fmod(fmod(a, b) + b, b)), @"sqrt": REA_SINGLE(sqrt(a)), @"log": REA_SINGLE(log(a)), @"sin": REA_SINGLE(sin(a)), @"cos": REA_SINGLE(cos(a)), @"tan": REA_SINGLE(tan(a)), @"acos": REA_SINGLE(acos(a)), @"asin": REA_SINGLE(asin(a)), @"atan": REA_SINGLE(atan(a)), @"exp": REA_SINGLE(exp(a)), @"round": REA_SINGLE(round(a)), @"abs": REA_SINGLE(fabs(a)), @"ceil": REA_SINGLE(ceil(a)), @"floor": REA_SINGLE(floor(a)), @"max": REA_REDUCE(MAX(a, b)), @"min": REA_REDUCE(MIN(a, b)), // logical @"and": ^(NSArray *inputNodes) { BOOL res = [[inputNodes[0] value] doubleValue]; for (NSUInteger i = 1; i < inputNodes.count && res; i++) { res = res && [[inputNodes[i] value] doubleValue]; } return res ? @(1.) : @(0.); }, @"or": ^(NSArray *inputNodes) { BOOL res = [[inputNodes[0] value] doubleValue]; for (NSUInteger i = 1; i < inputNodes.count && !res; i++) { res = res || [[inputNodes[i] value] doubleValue]; } return res ? @(1.) : @(0.); }, @"not": REA_SINGLE(!a), @"defined": ^(NSArray *inputNodes) { id val = [inputNodes[0] value]; id res = @(val != nil && !([val isKindOfClass:[NSNumber class]] && isnan([val doubleValue]))); return res; }, // comparing @"lessThan": REA_INFIX(a < b), @"eq": REA_INFIX(a == b), @"greaterThan": REA_INFIX(a > b), @"lessOrEq": REA_INFIX(a <= b), @"greaterOrEq": REA_INFIX(a >= b), @"neq": REA_INFIX(a != b), }; }); if ((self = [super initWithID:nodeID config:config])) { _input = config[@"input"]; _inputNodes = [NSMutableArray arrayWithCapacity:_input.count]; _op = OPS[config[@"op"]]; if (!_op) { RCTLogError(@"Operator '%@' not found", config[@"op"]); } } return self; } - (id)evaluate { for (NSUInteger i = 0; i < _input.count; i++) { _inputNodes[i] = [self.nodesManager findNodeByID:_input[i]]; } return _op(_inputNodes); } @end