Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bit shifting in swift generic function

Tags:

generics

swift

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?

like image 877
dustincarr Avatar asked Nov 03 '14 14:11

dustincarr


People also ask

What is generic function in Swift?

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.

How do you declare a generic variable in Swift?

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.

What is T type Swift?

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.

What are generics IOS?

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.


1 Answers

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!

like image 106
Nate Cook Avatar answered Nov 15 '22 06:11

Nate Cook