Created
February 13, 2019 21:00
-
-
Save AmitaiB/6bb63bae87dd80f5836db81a4ccd120e to your computer and use it in GitHub Desktop.
Drop-in, extendable Swift extension that allows for easy, clean number interoperability
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Give Int, CGFloats, and Floats a `doubleValue` property, like `NSNumber`.`doubleValue` | |
Original By Erica Sadun, (Swift Cookbook recipe 5-1), found here: https://gist.github.com/erica/2f6a38c844573c778b0f | |
Subsequent mutilations by Amitai Blickstein | |
*/ | |
//: Numbers that convert to other types | |
public protocol ConvertibleNumberType: DoubleRepresentable, NumberInitAble {} | |
// To extend the family to more types, add its implementation here. | |
public extension ConvertibleNumberType { | |
public var floatValue: Float { get {return Float(doubleValue)}} | |
public var intValue: Int { get {return lrint(doubleValue)}} | |
public var CGFloatValue: CGFloat { get {return CGFloat(doubleValue)}} | |
public var UInt32Value: UInt32 { get {return UInt32(doubleValue)}} | |
public var UIntValue: UInt { get {return UInt(doubleValue)}} | |
public var NSNumberValue: NSNumber { get {return NSNumber(value: doubleValue)}} | |
} | |
/// Numbers that can be fully represented as Doubles. | |
public protocol DoubleRepresentable { | |
var doubleValue: Double { get } | |
} | |
// MARK: - DoubleRepresentable | |
extension Double: ConvertibleNumberType { | |
public var doubleValue: Double {return self} | |
public init<T: ConvertibleNumberType>(_ value: T) { | |
self = value.doubleValue | |
} | |
} | |
extension Int: ConvertibleNumberType { | |
public var doubleValue: Double {return Double(self)} | |
public init<T: ConvertibleNumberType>(_ value: T) { | |
self = value.intValue | |
} | |
} | |
extension CGFloat: ConvertibleNumberType { | |
public var doubleValue: Double {return Double(self)} | |
public init<T: ConvertibleNumberType>(_ value: T) { | |
self = value.CGFloatValue | |
} | |
} | |
extension Float: ConvertibleNumberType { | |
public var doubleValue: Double {return Double(self)} | |
public init<T: ConvertibleNumberType>(_ value: T) { | |
self = value.floatValue | |
} | |
} | |
extension UInt32: ConvertibleNumberType { | |
public var doubleValue: Double {return Double(self)} | |
/// - warning: Will crash if value ≥ 0 is not true. | |
public init<T: ConvertibleNumberType>(_ value: T) { | |
print(" *** Warning: UInt generic inits are unsafe for invalid (negative) values. ***") | |
self = value.UInt32Value | |
} | |
} | |
extension UInt: ConvertibleNumberType { | |
public var doubleValue: Double { return Double(self) } | |
/// - warning: Will crash if value ≥ 0 is not true. | |
public init<T>(_ value: T) where T : ConvertibleNumberType { | |
print(" *** Warning: UInt generic inits are unsafe for invalid (negative) values. ***") | |
self = value.UIntValue | |
} | |
} | |
// MARK: - Convenience Helpers | |
// I do not want to think about the recursive conformance going on here. | |
/// Allows `T(someNumber)` | |
public protocol NumberInitAble { | |
init<T: ConvertibleNumberType>(_ value: T) | |
} | |
// MARK: - Operators | |
// MARK: Vanilla Arithmetic Operations | |
func +<T: ConvertibleNumberType, U: ConvertibleNumberType>(lhs: T?, rhs: U?) -> T { | |
return T((lhs?.doubleValue ?? 0.0) + (rhs?.doubleValue ?? 0.0)) | |
} | |
func -<T: ConvertibleNumberType, U: ConvertibleNumberType>(lhs: T?, rhs: U?) -> T { | |
return T((lhs?.doubleValue ?? 0.0) - (rhs?.doubleValue ?? 0.0)) | |
} | |
func *<T: ConvertibleNumberType, U: ConvertibleNumberType>(lhs: T?, rhs: U?) -> T { | |
return T((lhs?.doubleValue ?? 1.0) * (rhs?.doubleValue ?? 1.0)) | |
} | |
func /<T: ConvertibleNumberType, U: ConvertibleNumberType>(lhs: T?, rhs: U?) -> T { | |
return T((lhs?.doubleValue ?? 1.0) / (rhs?.doubleValue ?? 1.0)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment