Files
divkit/client/ios/DivKit/Expressions/Functions/MathFunctions.swift
T
pkurchatov 290a1febad reduced methods visibility
Немного причесал API в выражениях и разложил по папкам.
2022-09-13 16:18:22 +03:00

256 lines
5.8 KiB
Swift

import Foundation
enum MathFunctions: String, CaseIterable {
case div
case mod
case mul
case sub
case sum
case maxInteger
case minInteger
case maxNumber
case minNumber
case max
case min
case abs
case signum
case round
case floor
case ceil
case copySign
var declaration: [AnyCalcExpression.Symbol: AnyCalcExpression.SymbolEvaluator] {
[.function(rawValue, arity: function.arity): function.symbolEvaluator]
}
var function: Function {
switch self {
case .div:
return OverloadedFunction(
functions: [
FunctionBinary(impl: _divInt),
FunctionBinary(impl: _divDouble),
]
)
case .mod:
return OverloadedFunction(
functions: [
FunctionBinary(impl: _modInt),
FunctionBinary(impl: _modDouble),
]
)
case .mul:
return OverloadedFunction(
functions: [
FunctionVarUnary(impl: _mulInt),
FunctionVarUnary(impl: _mulDouble),
]
)
case .sub:
return OverloadedFunction(
functions: [
FunctionVarUnary(impl: _subInt),
FunctionVarUnary(impl: _subDouble),
]
)
case .sum:
return OverloadedFunction(
functions: [
FunctionVarUnary(impl: _sumInt),
FunctionVarUnary(impl: _sumDouble),
]
)
case .maxInteger:
return FunctionNullary(impl: _maxInteger)
case .minInteger:
return FunctionNullary(impl: _minInteger)
case .maxNumber:
return FunctionNullary(impl: _maxNumber)
case .minNumber:
return FunctionNullary(impl: _minNumber)
case .max:
return OverloadedFunction(
functions: [
FunctionVarUnary(impl: _maxInt),
FunctionVarUnary(impl: _maxDouble),
]
)
case .min:
return OverloadedFunction(
functions: [
FunctionVarUnary(impl: _minInt),
FunctionVarUnary(impl: _minDouble),
]
)
case .abs:
return OverloadedFunction(
functions: [
FunctionUnary(impl: _absInt),
FunctionUnary(impl: _absDouble),
]
)
case .signum:
return OverloadedFunction(
functions: [
FunctionUnary(impl: _signumInt),
FunctionUnary(impl: _signumDouble),
]
)
case .round:
return FunctionUnary(impl: _round)
case .floor:
return FunctionUnary(impl: _floor)
case .ceil:
return FunctionUnary(impl: _ceil)
case .copySign:
return OverloadedFunction(
functions: [
FunctionBinary(impl: _copySignInt),
FunctionBinary(impl: _copySignDouble),
]
)
}
}
}
private func _divInt(lhs: Int, rhs: Int) throws -> Int {
guard rhs != 0 else {
throw Error.divisionByZero("div", lhs, rhs).message
}
return lhs / rhs
}
private func _divDouble(lhs: Double, rhs: Double) throws -> Double {
guard !rhs.isApproximatelyEqualTo(0) else {
throw Error.divisionByZero("div", lhs, rhs).message
}
return lhs / rhs
}
private func _modInt(lhs: Int, rhs: Int) throws -> Int {
guard rhs != 0 else {
throw Error.divisionByZero("mod", lhs, rhs).message
}
return lhs % rhs
}
private func _modDouble(lhs: Double, rhs: Double) throws -> Double {
guard !rhs.isApproximatelyEqualTo(0) else {
throw Error.divisionByZero("mod", lhs, rhs).message
}
return fmod(lhs, rhs)
}
private func _mulInt(args: [Int]) throws -> Int {
args.reduce(1) { $0 * $1 }
}
private func _mulDouble(args: [Double]) throws -> Double {
args.reduce(1) { $0 * $1 }
}
private func _subInt(args: [Int]) throws -> Int {
args.dropFirst().reduce(args[0]) { $0 - $1 }
}
private func _subDouble(args: [Double]) throws -> Double {
args.dropFirst().reduce(args[0]) { $0 - $1 }
}
private func _sumInt(args: [Int]) throws -> Int {
args.reduce(0) { $0 + $1 }
}
private func _sumDouble(args: [Double]) throws -> Double {
args.reduce(0) { $0 + $1 }
}
private func _maxInteger() -> Int {
Int(Int32.max)
}
private func _minInteger() -> Int {
Int(Int32.min)
}
private func _maxNumber() -> Double {
Double.greatestFiniteMagnitude
}
private func _minNumber() -> Double {
Double.leastNonzeroMagnitude
}
private func _maxInt(args: [Int]) -> Int {
args.reduce(args[0]) { max($0, $1) }
}
private func _maxDouble(args: [Double]) -> Double {
args.reduce(args[0]) { max($0, $1) }
}
private func _minInt(args: [Int]) -> Int {
args.reduce(args[0]) { min($0, $1) }
}
private func _minDouble(args: [Double]) -> Double {
args.reduce(args[0]) { min($0, $1) }
}
private func _absInt(value: Int) -> Int {
abs(value)
}
private func _absDouble(value: Double) -> Double {
abs(value)
}
private func _signumInt(value: Int) -> Int {
value > 0 ? 1 : (value < 0 ? -1 : 0)
}
private func _signumDouble(value: Double) -> Double {
value.isApproximatelyGreaterThan(0) ? 1 : (value.isApproximatelyLessThan(0) ? -1 : 0)
}
private func _round(value: Double) -> Double {
round(value)
}
private func _floor(value: Double) -> Double {
floor(value)
}
private func _ceil(value: Double) -> Double {
ceil(value)
}
private func _copySignInt(lhs: Int, rhs: Int) -> Int {
guard rhs != 0 else {
return lhs
}
return Int(copysign(Double(lhs), Double(rhs)))
}
private func _copySignDouble(lhs: Double, rhs: Double) -> Double {
copysign(lhs, rhs)
}
private enum Error {
case typeMismatch(args: [Any])
case divisionByZero(String, Any, Any)
private var description: String {
switch self {
case let .typeMismatch(args):
return "Type mismatch \(args.map { "\($0)" }.joined(separator: " "))"
case let .divisionByZero(function, lhs, rhs):
return "Failed to evaluate [\(function)(\(lhs), \(rhs))]. Division by zero is not supported."
}
}
var message: AnyCalcExpression.Error {
AnyCalcExpression.Error.message(description)
}
}