Files
react-native-reanimated/ios/Nodes/REAOperatorNode.m
2018-08-16 17:09:13 +02:00

105 lines
3.2 KiB
Objective-C

#include <tgmath.h>
#import "REAOperatorNode.h"
#import "REANodesManager.h"
typedef id (^REAOperatorBlock)(NSArray<REANode *> *inputNodes);
#define REA_REDUCE(OP) ^(NSArray<REANode *> *inputNodes) { \
CGFloat acc = [[inputNodes[0] value] doubleValue]; \
for (NSUInteger i = 1; i < inputNodes.count; i++) { \
CGFloat a = acc, b = [[inputNodes[i] value] doubleValue]; \
acc = OP; \
} \
return @(acc); \
}
#define REA_SINGLE(OP) ^(NSArray<REANode *> *inputNodes) { \
CGFloat a = [[inputNodes[0] value] doubleValue]; \
return @(OP); \
}
#define REA_INFIX(OP) ^(NSArray<REANode *> *inputNodes) { \
CGFloat a = [[inputNodes[0] value] doubleValue]; \
CGFloat b = [[inputNodes[1] value] doubleValue]; \
return @(OP); \
}
@implementation REAOperatorNode {
NSArray<NSNumber *> *_input;
NSMutableArray<REANode *> *_inputNodes;
REAOperatorBlock _op;
}
- (instancetype)initWithID:(REANodeID)nodeID config:(NSDictionary<NSString *,id> *)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(fmodf(fmodf(a, b) + b, b)),
@"sqrt": REA_SINGLE(sqrt(a)),
@"sin": REA_SINGLE(sin(a)),
@"cos": REA_SINGLE(cos(a)),
@"exp": REA_SINGLE(exp(a)),
@"round": REA_SINGLE(round(a)),
// logical
@"and": ^(NSArray<REANode *> *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<REANode *> *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<REANode *> *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