Skip to content

Instantly share code, notes, and snippets.

@CommanderPho
Forked from wircho/ThrowingOperators.swift
Last active June 27, 2018 02:51
Show Gist options
  • Save CommanderPho/f975e54fbe10d8f1d5f483bf4fa734a7 to your computer and use it in GitHub Desktop.
Save CommanderPho/f975e54fbe10d8f1d5f483bf4fa734a7 to your computer and use it in GitHub Desktop.
Arithmetic operators that throw on integer type overflow and floating point type errors.
//
// ThrowingMathematicalOperators.swift
// Dose
//
// Created by Pho Hale on 6/26/18.
// Copyright © 2018 Pho Hale. All rights reserved.
//
import Darwin
import Swift
import CoreGraphics
// MARK: Operators
infix operator &&+: AdditionPrecedence
infix operator &&-: AdditionPrecedence
infix operator &&*: MultiplicationPrecedence
infix operator &&/: MultiplicationPrecedence
infix operator &&%: MultiplicationPrecedence
prefix operator &&?
// MARK: Error type
public struct ArithmeticOperationError: Error {
public enum OverflowType {
case overflow
case nan
case infinity
}
public enum Operation {
case addition
case subtraction
case multiplication
case division
case remainder
case other(String?)
}
let type:OverflowType
let operation:Operation
init(_ type:OverflowType, _ operation:Operation) {
self.type = type
self.operation = operation
}
}
// MARK: Integer operator implementations
public func &&+<T:FixedWidthInteger>(lhs:T,rhs:T) throws -> T {
let (result,overflow) = lhs.addingReportingOverflow(rhs)
guard !overflow else {
throw ArithmeticOperationError(.overflow,.addition)
}
return result
}
public func &&-<T:FixedWidthInteger>(lhs:T,rhs:T) throws -> T {
let (result,overflow) = lhs.subtractingReportingOverflow(rhs)
guard !overflow else {
throw ArithmeticOperationError(.overflow,.subtraction)
}
return result
}
public func &&*<T:FixedWidthInteger>(lhs:T,rhs:T) throws -> T {
let (result,overflow) = lhs.multipliedReportingOverflow(by: rhs)
guard !overflow else {
throw ArithmeticOperationError(.overflow,.multiplication)
}
return result
}
public func &&/<T:FixedWidthInteger>(lhs:T,rhs:T) throws -> T {
// let (result,overflow) = T.divideWithOverflow(lhs,rhs)
let (result,overflow) = lhs.remainderReportingOverflow(dividingBy: rhs)
guard !overflow else {
throw ArithmeticOperationError(.overflow,.division)
}
return result
}
public func &&%<T:FixedWidthInteger>(lhs:T,rhs:T) throws -> T {
// let (result,overflow) = T.remainderWithOverflow(lhs,rhs)
let (result,overflow) = lhs.remainderReportingOverflow(dividingBy: rhs)
guard !overflow else {
throw ArithmeticOperationError(.overflow,.remainder)
}
return result
}
// MARK: Floating point helpers
private func enforce<T:FloatingPoint>(value:T,_ op:ArithmeticOperationError.Operation) throws -> T {
guard !value.isInfinite else {
throw ArithmeticOperationError(.infinity,op)
}
guard !value.isNaN else {
throw ArithmeticOperationError(.nan,op)
}
return value
}
public func throwing<T:FloatingPoint>(value:T,_ debug:String? = nil) throws -> T {
return try enforce(value: value, .other(debug))
}
public prefix func &&?<T:FloatingPoint>(value:T) throws -> T {
return try throwing(value: value)
}
// MARK: Encapsulating Double, Float, and CGFloat
public protocol FloatingPointArithmeticType: FloatingPoint {
static func +(_:Self,_:Self) -> Self
static func -(_:Self,_:Self) -> Self
static func *(_:Self,_:Self) -> Self
static func /(_:Self,_:Self) -> Self
}
extension Double: FloatingPointArithmeticType {}
extension Float: FloatingPointArithmeticType {}
extension CGFloat: FloatingPointArithmeticType {}
// MARK: Floating point operator implementations
public func &&+<T:FloatingPointArithmeticType>(lhs:T,rhs:T) throws -> T {
return try enforce(value: lhs + rhs, .addition)
}
public func &&-<T:FloatingPointArithmeticType>(lhs:T,rhs:T) throws -> T {
return try enforce(value: lhs - rhs, .subtraction)
}
public func &&*<T:FloatingPointArithmeticType>(lhs:T,rhs:T) throws -> T {
return try enforce(value: lhs * rhs, .multiplication)
}
public func &&/<T:FloatingPointArithmeticType>(lhs:T,rhs:T) throws -> T {
return try enforce(value: lhs / rhs, .division)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment