web-dev-qa-db-fra.com

Int à UInt (et vice versa) diffusion de bits dans Swift

Je cherche un moyen direct de convertir les valeurs de bits d'un Int en UInt et inversement. Par exemple (en utilisant les nombres entiers de 8 bits pour des raisons de simplicité), je souhaite atteindre les objectifs suivants:

let unsigned: UInt8 = toUInt8(-1)  // unsigned is 255 or 0xff
let signed:   Int8  = toInt8(0xff) // signed is -1 

Au début, je suis sorti avec la solution suivante:

let unsigned = unsafeBitCast(Int8(-1), UInt8.self)
let signed   = unsafeBitCast(UInt8(0xff), Int8.self)

Mais Apple dans la documentation "unsafeBitCast ()" indique ce qui suit:

.. Caution :: Enlève les garanties du système de types de Swift; utiliser avec soin extrême. Il y a presque toujours une meilleure façon de faire n'importe quoi.

Est-ce que quelqu'un a le meilleur moyen?

20
Michele Dall'Agata

Tu peux faire:

let unsigned = UInt8(bitPattern: Int8(-1)) // -> 255
let signed   = Int8(bitPattern: UInt8(0xff)) // -> -1

De nombreux initialiseurs similaires existent:

extension Int8 {
    init(_ v: UInt8)
    init(_ v: UInt16)
    init(truncatingBitPattern: UInt16)
    init(_ v: Int16)
    init(truncatingBitPattern: Int16)
    init(_ v: UInt32)
    init(truncatingBitPattern: UInt32)
    init(_ v: Int32)
    init(truncatingBitPattern: Int32)
    init(_ v: UInt64)
    init(truncatingBitPattern: UInt64)
    init(_ v: Int64)
    init(truncatingBitPattern: Int64)
    init(_ v: UInt)
    init(truncatingBitPattern: UInt)
    init(_ v: Int)
    init(truncatingBitPattern: Int)
    init(bitPattern: UInt8)
}
36
rintaro

J'ai pris la route de l'algèbre. Les tests ont été pénibles, car il est facile d’obtenir un dépassement de capacité en cas de frappe trop forte pour interrompre l’exécution. PlayGround a renvoyé une valeur négative de la fonction toUInt. Quoi qu'il en soit, c'est ce que j'ai fini avec:

func toUint(signed: Int) -> UInt {

    let unsigned = signed >= 0 ?
        UInt(signed) :
        UInt(signed  - Int.min) + UInt(Int.max) + 1

    return unsigned
}

func toInt(unsigned: UInt) -> Int {

    let signed = (unsigned <= UInt(Int.max)) ?
        Int(unsigned) :
        Int(unsigned - UInt(Int.max) - 1) + Int.min

    return signed
}

Je les ai testées avec toutes les valeurs extrêmes (UInt.min, UInt.max, Int.min, Int.max) et lorsque XCode ne devient pas fou, cela semble fonctionner, mais cela semble trop compliqué. Bizarrement, la diffusion de bits UInt à Int pourrait être obtenue simplement avec la propriété hashvalue comme dans:

signed = UInt.max.hashValue // signed is -1

Mais évidemment, il n’est pas garanti de toujours travailler (cela devrait, mais je préfère ne pas prendre de risque). 

Toute autre idée sera appréciée.

2
Michele Dall'Agata

numericCast(...) est ce que vous recherchez. C'est un ensemble de fonctions génériques qui convertit à partir de types de nombres différents. Il choisit la bonne implémentation en fonction des types de son argument et du type de retour.

0
stigi