Skip to content

Instantly share code, notes, and snippets.

@tcldr
Last active November 10, 2018 17:16
Show Gist options
  • Save tcldr/f25a1a147b07774ae5bc5be01c5e157b to your computer and use it in GitHub Desktop.
Save tcldr/f25a1a147b07774ae5bc5be01c5e157b to your computer and use it in GitHub Desktop.
Range based clamping for `FloatingPoint` types.
// FloatingPoint extension
extension FloatingPoint {
func clamped<T: ClampableRangeExpression>(to range: T) -> Self where T.Bound == Self {
return range.clamping(self)
}
}
// RangeExpression extension
protocol ClampableRangeExpression: RangeExpression where Bound: FloatingPoint {
func clamping(_ value: Bound) -> Bound
}
// Conformance for various Range Types
extension PartialRangeFrom: ClampableRangeExpression where Bound: FloatingPoint {
func clamping(_ value: Bound) -> Bound {
return contains(value) ? value : lowerBound
}
}
extension PartialRangeThrough: ClampableRangeExpression where Bound: FloatingPoint {
func clamping(_ value: Bound) -> Bound {
return contains(value) ? value : upperBound
}
}
extension ClosedRange: ClampableRangeExpression where Bound: FloatingPoint {
func clamping(_ value: Bound) -> Bound {
return (lowerBound...).clamping((...upperBound).clamping(value))
}
}
extension Range: ClampableRangeExpression where Bound: FloatingPoint {
func clamping(_ value: Bound) -> Bound {
guard !isEmpty else { return .nan }
return (lowerBound...).clamping((..<upperBound).clamping(value))
}
}
extension PartialRangeUpTo: ClampableRangeExpression where Bound: FloatingPoint {
func clamping(_ value: Bound) -> Bound {
return (...upperBound.nextDown).clamping(value)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment