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?
Swift Generics allows us to create a single function and class (or any other types) that can be used with different data types. This helps us to reuse our code.
Generics allow you to declare a variable which, on execution, may be assigned to a set of types defined by us. In Swift, an array can hold data of any type. If we need an array of integers, strings, or floats, we can create one with the Swift standard library.
The placeholder type T is used in the function declaration. It tells Swift that this function can find any item in any array, as long as the foundItem and items in the array are of the same type. This makes sense — you want to look for a T value in an array of T values.
Apple doc says: Generic code enables you to write flexible, reusable functions and types that can work with any type. You can write code that avoids duplication by using generics in most cases.
I have a blog post on this topic that goes into more detail, but essentially there are three steps:
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)
}
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 {}
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With