Skip to content

Instantly share code, notes, and snippets.

@AmitaiB
Created February 13, 2019 21:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AmitaiB/6bb63bae87dd80f5836db81a4ccd120e to your computer and use it in GitHub Desktop.
Save AmitaiB/6bb63bae87dd80f5836db81a4ccd120e to your computer and use it in GitHub Desktop.
Drop-in, extendable Swift extension that allows for easy, clean number interoperability
/**
* 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