Files
divkit/client/ios/DivKit/Expressions/Functions/MathFunctions.swift
T
pkurchatov 976bc60b76 Expression errors refactoring
0f64602cade0949128541074d27144a4f680418a
2024-05-13 19:41:36 +03:00

243 lines
5.4 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 function: Function {
switch self {
case .div:
OverloadedFunction(
functions: [
FunctionBinary(impl: _divInt),
FunctionBinary(impl: _divDouble),
]
)
case .mod:
OverloadedFunction(
functions: [
FunctionBinary(impl: _modInt),
FunctionBinary(impl: _modDouble),
]
)
case .mul:
OverloadedFunction(
functions: [
FunctionVarUnary(impl: _mulInt),
FunctionVarUnary(impl: _mulDouble),
]
)
case .sub:
OverloadedFunction(
functions: [
FunctionVarUnary(impl: _subInt),
FunctionVarUnary(impl: _subDouble),
]
)
case .sum:
OverloadedFunction(
functions: [
FunctionVarUnary(impl: _sumInt),
FunctionVarUnary(impl: _sumDouble),
]
)
case .maxInteger:
ConstantFunction(Int.max)
case .minInteger:
ConstantFunction(Int.min)
case .maxNumber:
ConstantFunction(Double.greatestFiniteMagnitude)
case .minNumber:
ConstantFunction(Double.leastNonzeroMagnitude)
case .max:
OverloadedFunction(
functions: [
FunctionVarUnary(impl: _maxInt),
FunctionVarUnary(impl: _maxDouble),
]
)
case .min:
OverloadedFunction(
functions: [
FunctionVarUnary(impl: _minInt),
FunctionVarUnary(impl: _minDouble),
]
)
case .abs:
OverloadedFunction(
functions: [
FunctionUnary(impl: _absInt),
FunctionUnary(impl: _absDouble),
]
)
case .signum:
OverloadedFunction(
functions: [
FunctionUnary(impl: _signumInt),
FunctionUnary(impl: _signumDouble),
]
)
case .round:
FunctionUnary(impl: _round)
case .floor:
FunctionUnary(impl: _floor)
case .ceil:
FunctionUnary(impl: _ceil)
case .copySign:
OverloadedFunction(
functions: [
FunctionBinary(impl: _copySignInt),
FunctionBinary(impl: _copySignDouble),
]
)
}
}
}
private func _divInt(lhs: Int, rhs: Int) throws -> Int {
guard rhs != 0 else {
throw divisionByZeroError()
}
return lhs / rhs
}
private func _divDouble(lhs: Double, rhs: Double) throws -> Double {
guard !rhs.isApproximatelyEqualTo(0) else {
throw divisionByZeroError()
}
return lhs / rhs
}
private func _modInt(lhs: Int, rhs: Int) throws -> Int {
guard rhs != 0 else {
throw divisionByZeroError()
}
return lhs % rhs
}
private func _modDouble(lhs: Double, rhs: Double) throws -> Double {
guard !rhs.isApproximatelyEqualTo(0) else {
throw divisionByZeroError()
}
return fmod(lhs, rhs)
}
private func _mulInt(args: [Int]) throws -> Int {
try args.reduce(1) {
if case let (result, overflow) = $0.multipliedReportingOverflow(by: $1), !overflow {
return result
}
throw ExpressionError.integerOverflow()
}
}
private func _mulDouble(args: [Double]) throws -> Double {
args.reduce(1, *)
}
private func _subInt(args: [Int]) throws -> Int {
try args.dropFirst().reduce(args[0]) {
if case let (result, overflow) = $0.subtractingReportingOverflow($1), !overflow {
return result
}
throw ExpressionError.integerOverflow()
}
}
private func _subDouble(args: [Double]) throws -> Double {
args.dropFirst().reduce(args[0], -)
}
private func _sumInt(args: [Int]) throws -> Int {
try args.reduce(0) {
if case let (result, overflow) = $0.addingReportingOverflow($1), !overflow {
return result
}
throw ExpressionError.integerOverflow()
}
}
private func _sumDouble(args: [Double]) throws -> Double {
args.reduce(0, +)
}
private func _maxInt(args: [Int]) -> Int {
args.reduce(args[0], max)
}
private func _maxDouble(args: [Double]) -> Double {
args.reduce(args[0], max)
}
private func _minInt(args: [Int]) -> Int {
args.reduce(args[0], min)
}
private func _minDouble(args: [Double]) -> Double {
args.reduce(args[0], min)
}
private func _absInt(value: Int) throws -> Int {
guard value >= -Int.max else {
throw ExpressionError.integerOverflow()
}
return 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) throws -> Int {
guard lhs >= -Int.max && rhs >= 0 || lhs >= Int.min && rhs < 0 else {
throw ExpressionError.integerOverflow()
}
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 func divisionByZeroError() -> Error {
ExpressionError("Division by zero is not supported.")
}