dustincarr
dustincarr

Reputation: 1415

Bit shifting in swift generic function

I am trying to write a generic function that requires bit shifting operations. I am getting behavior that I don't understand. Here is a simple function that demonstrates the problem.

func testBytes<T: IntegerType>(bytesIn: [UInt8], inout dataOut: T){

let outputSize = sizeof(T)
var temp: T = 0
dataOut = 0
temp = bytesIn[0] as T
temp = temp << 1

}

If I do this, then the last line gives me an error in xcode "T is not convertible to Int".

I can change the last line to temp = temp << (1 as T)

And then the error for this line changes to "T is not convertible to UInt8"

Neither one of these error messages make sense to me in this context. Is there something I can do to enable bit shifting on a generic type?

Upvotes: 5

Views: 336

Answers (1)

Nate Cook
Nate Cook

Reputation: 93276

I have a blog post on this topic that goes into more detail, but essentially there are three steps:

  1. Create a new protocol with the bitshift operators and a constructor from UInt8:

    protocol BitshiftOperationsType {
        func <<(lhs: Self, rhs: Self) -> Self
        func >>(lhs: Self, rhs: Self) -> Self
        init(_ val: UInt8)
    }
    
  2. Declare conformance with an extension on each of the integer types - easy since they already implement everything in BitshiftOperationsType:

    extension Int    : BitshiftOperationsType {}
    extension Int8   : BitshiftOperationsType {}
    extension Int16  : BitshiftOperationsType {}
    extension Int32  : BitshiftOperationsType {}
    extension Int64  : BitshiftOperationsType {}
    extension UInt   : BitshiftOperationsType {}
    extension UInt8  : BitshiftOperationsType {}
    extension UInt16 : BitshiftOperationsType {}
    extension UInt32 : BitshiftOperationsType {}
    extension UInt64 : BitshiftOperationsType {}
    
  3. Add a generic constraint so T conforms to your new protocol:

    func testBytes<T: IntegerType where T: BitshiftOperationsType>(bytesIn: [UInt8], inout dataOut: T){
        let outputSize = sizeof(T)
        var temp: T = 0
        dataOut = 0
        temp = T(bytesIn[0])
        temp = temp << 1
    }
    

Thanks to Martin R. for the fix for the gross bit I had here before!

Upvotes: 7

Related Questions