Extending Generic Integer Types in Swift
extension Comparable {
func clamp(var minimum: Self, var _ maximum: Self) -> Self {
if maximum < minimum { swap(&maximum, &minimum) }
if self < minimum { return minimum }
if self > maximum { return maximum }
return self
}
}
While Swift 2.0 is still in beta I suggest you to add extensions like you illustrated. You will have to copy-paste the same code for Int
, Int64
etc, but there is no other way to do what you want at the moment.
Once Swift 2.0 is out you will be able to do this
extension IntegerType {
mutating func clamp(minimum:Self, maximum:Self) {
if self < minimum { self = minimum }
if self > maximum { self = maximum }
}
}
If you can wait with the release of your app until some time in September then I encourage you to start using Swift 2.0 right now.
Update
With Swift 2.0 you can also add extension to Comparable
protocol which will ensure that clamp()
is available for other types such as Double
, Float
, etc
extension Comparable {
mutating func clamp(minimum:Self, maximum:Self) {
if self < minimum { self = minimum }
if self > maximum { self = maximum }
}
}
By way of example, here is an integer implementation of clamped
that also applies generically to anything that can use it:
extension Comparable
{
func clamped(from lowerBound: Self, to upperBound: Self) -> Self {
return min(max(self, lowerBound), upperBound)
}
func clamped(to range: ClosedRange<Self>) -> Self {
return min(max(self, range.lowerBound), range.upperBound)
}
}
extension Strideable where Self.Stride: SignedInteger
{
func clamped(to range: CountableClosedRange<Self>) -> Self {
return min(max(self, range.lowerBound), range.upperBound)
}
}
And the test cases:
7.clamped(from: 3, to: 6) // 6
7.clamped(to: 3 ... 6) // 6
7.clamped(to: 3 ... 7) // 7
7.clamped(to: 3 ... 8) // 7
7.0.clamped(to: 3.0 ... 6.0) // 6
7.0.clamped(to: 3.0 ... 7.0) // 7
7.0.clamped(to: 3.0 ... 8.0) // 7
For Swift 2, see Andriy Gordiychuk's answer, which will be correct then. If you require Swift 1, then this cannot be done with extensions, and must be done with free functions. This is why there are so many free functions in stdlib that became extensions in Swift 2.
For Swift 1, what you have to do is:
func clamp<T:Comparable>(value: T, #minimum:T, #maximum:T) -> T {
if value < minimum { return minimum }
if value > maximum { return maximum }
return value
}
If you prefer modifying the value (as Andriy's example does), you can do it this way:
func clamp<T:Comparable>(inout value: T, #minimum:T, #maximum:T) {
if value < minimum { value = minimum }
else if value > maximum { value = maximum }
}
Otherwise you have to write an extension on every type. It's the only other answer in Swift 1. Swift 2 is much better.