2016-09-22 4 views
0

私は以下のポイントを超えて進歩することができませんでした。swift 2.2で整数配列の汎用変換を行うことは可能ですか?

私が取得しています:私は「T」に「要素」からデータを移動していますライン上

Cannot convert value of type 'Element' to expected argument type 'IntegerLiteralType' (aka 'Int') 

を。また、私はまだUIntに切り捨てる方法を理解していません。

ご協力いただければ幸いです。

protocol Truncating { 
    init(truncatingBitPattern: IntegerLiteralType) 
} 

extension Int { 
    init(truncatingBitPattern value: Int) { self.init(truncatingBitPattern: value.toIntMax()) } 
} 

protocol Bitshiftable { 
    func <<(lhs: Self, rhs: Self) -> Self 
    func >>(lhs: Self, rhs: Self) -> Self 
    func <<=(inout lhs: Self, rhs: Self) 
    func >>=(inout lhs: Self, rhs: Self) 
} 

protocol ArrayConvertable: IntegerType, Bitshiftable, Truncating {} 

extension Int : ArrayConvertable {} 
extension Int8 : ArrayConvertable {} 
extension Int16 : ArrayConvertable {} 
extension Int32 : ArrayConvertable {} 
extension Int64 : ArrayConvertable {} 
//extension UInt : ArrayConvertable {} 
extension UInt8 : ArrayConvertable {} 
extension UInt16 : ArrayConvertable {} 
extension UInt32 : ArrayConvertable {} 
extension UInt64 : ArrayConvertable {} 

extension Array where Element: ArrayConvertable { 
    func toInt<T: ArrayConvertable>() -> T? 
    { 
     let targetSize = sizeof(T) 
     let sourceSize = sizeof(Element) 
     let sourceByteCount = count * sourceSize 
     guard targetSize == sourceByteCount else { return nil } 

     var n: T = 0 
     for e in self { 
      var dataChunk = e 
      for i in 0..<sourceSize { 
       n = n | T(truncatingBitPattern: dataChunk) 
       if i + 1 < sourceSize { 
        n = n << 8 
        dataChunk = dataChunk >> 8 
       } 
      } 
     } 

     return n 
    } 
} 

func test() { 
    let a8: [UInt8] = [0xab, 0xba, 0xda, 0xba, 0xd0, 0xd1, 0xd2, 0xd3, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10] 
    let a16: [UInt16] = [0xabba, 0xdaba, 0xd0d1, 0xd2d3, 0xfedc, 0xba98, 0x7654, 0x3210] 
    let a32: [UInt32] = [0xabbadaba, 0xd0d1d2d3, 0xfedcba98, 0x] 
    let a64: [UInt64] = [0xabbadabad0d1d2d3, 0xfedcba] 

    var n8: UInt8 = 0 
    var n16: UInt16 = 0 
    var n32: UInt32 = 0 
    var n64: UInt64 = 0 

    print("--- 08 bit source") 
    n8 = a8.toInt()! 
    n16 = a8.toInt()! 
    n32 = a8.toInt()! 
    n64 = a8.toInt()! 
    print(n8, n16, n32, n64) 

    print("--- 16 bit source") 
    n8 = a16.toInt()! 
    n16 = a16.toInt()! 
    n32 = a16.toInt()! 
    n64 = a16.toInt()! 
    print(n8, n16, n32, n64) 

    print("--- 32 bit source") 
    n8 = a32.toInt()! 
    n16 = a32.toInt()! 
    n32 = a32.toInt()! 
    n64 = a32.toInt()! 
    print(n8, n16, n32, n64) 

    print("--- 64 bit source") 
    n8 = a64.toInt()! 
    n16 = a64.toInt()! 
    n32 = a64.toInt()! 
    n64 = a64.toInt()! 
    print(n8, n16, n32, n64) 
} 

test() 
+0

:入力配列はシングルには大きすぎるので、あなたのアサーション 'はTargetSize == sourceByteCount'はいつもの例に失敗します8/16/32/64ビット整数。または結果がターゲット型の*配列*ですか? –

+0

入力が 'let a32:[UInt32] = [0x01020304、0x05060708、0x090a0b0c、0x0d0e0f10]'であり、ターゲットタイプが 'UInt16'の場合、どのような結果になるでしょうか?ターゲットタイプ 'UInt64'に対しては? –

+0

@MartinRボディにいくつかのバグがありますが、targetがUInt16でsourceが[UInt8] .count == 2だった場合、targetSize == sourceByteCountです。この関数の結果は常に整数の1つです。 –

答えて

1

ここでは、データを再解釈することのできる解決策があります。 ないプロトコルが必要とされている:

extension Array where Element: IntegerType { 
    func toInt<T: IntegerType>() -> T? { 
     guard sizeof(T) <= count * sizeof(Element) else { return nil } 
     return UnsafePointer<T>(self).memory 
    } 
} 

例:

にかかわらず、実装の
let a32: [UInt32] = [0x11223344, 0x55667788, 0x99AABBCC, 0xDDEEFF00] 
if let u16: UInt16 = a32.toInt() { 
    print(String(format:"%#04x", u16)) // 0x3344 
} 
+0

これは本当にエレガントです。 1つの潜在的な落とし穴は、配列が連続していることが保証されていないことです。これはあなたの例では問題ではありませんが、例として[UInt8]からUInt64に行くときかもしれません。 –

+0

@SeanVikoren: 'UnsafePointer (self)'のように)ポインタをとる関数に配列を渡すと、要素の連続する記憶域のアドレスが渡されることは間違いありません。* –

+0

コード!ありがとうございました。 –

関連する問題