Brad Dwyer
Brad Dwyer

Reputation: 6504

Check if Swift genericized number is above a certain percentage of its maximum value

I'm trying to write an extension for a genericized class. I want to be able to determine whether a variable of type T's value is above a certain percentage of its maximum value.

I'm having trouble a) figuring out how to get the max value for the type, and b) getting the types converted right for the comparison.

public class CustomClass<T:BinaryInteger> { 
    public var someValue:T
    ...
}
extension CustomClass {
    func isOver(threshold:Float) {
        // defined for threshold between -1 and +1
        let convertedThreshold:Float = threshold * Float(T.MAX_VALUE)
        return self.someValue > T(clamping: convertedThreshold)
    }
}

Right now I'm stuck on getting the max value of a variable of type T. The BinaryInteger docs mention T.min and T.max but those seem to not actually be defined.

For clarity:

If threshold is 0.5 and T is of type UInt8 I want to return true if the variable is over 127. But if T is of type UInt16 I want to return true if the variable is over 32,767.

Upvotes: 1

Views: 250

Answers (2)

Martin R
Martin R

Reputation: 539965

As JeremyP said, you'll need to restrict T to the FixedWidthInteger protocol, which has a required max property.

For unsigned integer types, the conversation to Float (or Double) can be done via the largest unsigned integer type, UInt64:

extension CustomClass where T: UnsignedInteger {
    func isOver(threshold: Float) -> Bool {
        return Float(UInt64(self.someValue)) > threshold * Float(UInt64(T.max))
    }
}

(and via Int64 for signed integer types).

Full self-contained example:

public class CustomClass<T:FixedWidthInteger> {
    public var someValue: T = 0
}

extension CustomClass where T: UnsignedInteger {
    func isOver(threshold: Float) -> Bool {
        return Float(UInt64(self.someValue)) > threshold * Float(UInt64(T.max))
    }
}

let x = CustomClass<UInt16>()
x.someValue = 50_000
print(x.isOver(threshold: 0.5)) // true

Upvotes: 3

JeremyP
JeremyP

Reputation: 86661

BinaryInteger does not have min and max but FixedWidthInteger does. All the built in integer types have this protocol.

There is a further problem that I haven't figured out yet. It's not easy to convert an arbitrary type that conforms to FixedWidthInteger to a Float or Double.

Upvotes: 3

Related Questions