[swift-evolution] [Pre-proposal] Standard Protocol for Bitwise Shifts and Binary-based Integers

Haravikk swift-evolution at haravikk.com
Mon Jan 18 06:45:48 CST 2016

So I recently discovered that the shift operators no longer appear to be defined anywhere, i.e- they seem to only be implemented by convention rather than being required by a protocol, which doesn’t seem ideal. The problem with this is that I wanted to implement some bitwise operations but there’s no longer an obvious place to do this, and I ended up having to implement my own concept of a BitwiseIntegerType, as you can see in the example below:

protocol BitwiseIntegerType : BitwiseOperationsType, IntegerType {
    init(_ value:Int)
    init(_ value:UInt)

    func << (lhs:Self, rhs:Self) -> Self
    func >> (lhs:Self, rhs:Self) -> Self
    func <<= (inout lhs:Self, rhs:Self)
    func >>= (inout lhs:Self, rhs:Self)

extension BitwiseIntegerType {
    static var allOnes:Self { return ~Self.allZeros }
    static var numberOfBits:UInt { return UInt(sizeof(Self) * 8) }

    static var mostSignificantBit:Self { return Self.allOnes << Self(Self.numberOfBits - 1) }

    var leadingZeros:UInt {
        if self == Self.allZeros { return Self.numberOfBits }

        var value = self
        var width = Self.numberOfBits
        var mask = Self.allOnes
        var zeros:UInt = 0

        while (value & Self.mostSignificantBit) == Self.allZeros {
            if (value & mask) == Self.allZeros {
                zeros += width
                value <<= Self(width)
            } else {
                width /= 2
                mask <<= Self(width)

        return zeros

extension Int : BitwiseIntegerType {}
extension Int8 : BitwiseIntegerType {}
extension Int16 : BitwiseIntegerType {}
extension Int32 : BitwiseIntegerType {}
extension Int64 : BitwiseIntegerType {}

extension UInt : BitwiseIntegerType {}
extension UInt8 : BitwiseIntegerType {}
extension UInt16 : BitwiseIntegerType {}
extension UInt32 : BitwiseIntegerType {}
extension UInt64 : BitwiseIntegerType {}

Int64.mostSignificantBit    // -9223372036854775808
1234567.leadingZeros        // 43

I think that the best solution would be to add the shift operators to BitwiseOperationsType, while declaring a BitwiseIntegerType similar to what I’ve done above that groups BitwiseOperationsType with IntegerType to create a distinction between binary-based integers and integers that could be based on some other mechanism in future, as well as to declare the required initializers from Int and UInt types. This gives more flexibility in defining higher level protocol extensions that rely on the full range of bitwise operations, without having to move any of it further up (iirc some of these operators used to be in IntegerType).

Either way, the shift operators are currently declared by convention, which I don’t think is right, as they should surely be declared as a requirement somewhere.

Also, ignore the actual implementation of leadingZeros, it may not be the most efficient method, it’s just a useful illustration of something that can be done with the protocol declarations, I’ve also omitted warnings and such to keep things simple.

Just wondering what others think? One other issue I’m unsure about is that the required Int and Uint initialiizers should probably be of the truncatingBitPattern type for bitwise operations, but I wasn’t sure how to handle adding that to the types that don’t currently have these initializers (i.e- the 64-bit types that don’t need them since they can’t currently be initialized from anything bigger).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160118/3e38485b/attachment.html>

More information about the swift-evolution mailing list