mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
243 lines
5.4 KiB
Swift
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.")
|
|
}
|