Convertir le tableau 2D de Swift en tableau 2D de C

$ swift --version
Apple Swift version 4.0 (swiftlang-900.0.63.10 clang-900.0.36)
Target: x86_64-apple-macosx10.9

Swift est pratique car il facilite l'appel des fonctions du langage C. Vous pouvez également passer le ʻArray `de Swift à une fonction qui reçoit un pointeur en C, donc passer un tableau est facile.

Ceci est réalisé par le mécanisme selon lequel ʻArray est implicitement converti en ʻUnsafePointer <T> dans la partie appel de fonction.

Mais quand il s'agit d'un tableau à deux dimensions, cela ne fonctionne pas. Les pointeurs doubles sont utilisés lors de la réception d'un tableau à deux dimensions en C. Par exemple en C

void f0(const int * const * p);

Du point de vue de Swift, la fonction définie comme

func f0(_ p: UnsafePointer<UnsafePointer<CInt>?>!)

Est interprété comme. D'un autre côté, s'il y a un let arr: Array <Array <CInt >> du côté Swift, ce qui suit ne fonctionnera pas.

let arr: Array<Array<CInt>> = [ [0, 1, 2], [3, 4, 5] ]
f0(arr) //Erreur de compilation

Parce que, ce que vous obtenez en convertissant implicitement ʻArray <Array > `en un pointeur est

UnsafePointer<Array<CInt>>

Et

UnsafePointer<UnsafePointer<CInt>?>

Parce que ce n'est pas.

Donc, si vous regardez la transformation qui prend ʻUnsafePointer de ʻArray <T>,

func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<Array.Element>) throws -> R) rethrows -> R

Peut être trouvé. Vous voudrez peut-être l'utiliser pour écrire du code comme celui-ci: Ceci ** compile mais ne devrait pas. ** **

let arr: Array<Array<CInt>> = [ [0, 1, 2], [3, 4, 5] ]
let bufPtrArr: Array<UnsafeBufferPointer<CInt>> = arr.map {
    return $0.withUnsafeBufferPointer { $0 }
}
let ptrArr: Array<UnsafePointer<CInt>?> = bufPtrArr.map { $0.baseAddress }
f0(ptrArr)

En effet, le pointeur passé à la fermeture de l'argument de la méthode withUnsafeBufferPointer ne doit être utilisé que pendant l'exécution de cette méthode.

C'est une utilisation pour les appels récursifs car vous devez convertir les tableaux un par un en pointeurs, qui ne peuvent être utilisés que pendant withUnsafeBufferPointer. Après avoir converti un tableau avec withUnsafeBufferPointer, la procédure consiste à construire un tableau de pointeurs en convertissant le tableau suivant dans la méthode.

Ce processus récursif est difficile à écrire plusieurs fois, alors faisons-en une méthode d'extension de ʻArraypour la réutilisation, et récupérons ʻArray <UnsafeBufferPointer <T >>à partir de ʻArray <Array >J'ai crééwithUnsafeBufferPointerArray`.

extension Array {
    public func withUnsafeBufferPointerArray<T, R>(_ body: (Array<UnsafeBufferPointer<T>>) -> R) -> R
        where Element == Array<T>
    {
        var buffers = Array<UnsafeBufferPointer<T>>()
        var result: R?
        
        func recurse(body: (Array<UnsafeBufferPointer<T>>) -> R)
        {
            let i = buffers.count
            guard i < self.count else {
                result = body(buffers)
                return
            }
            self[i].withUnsafeBufferPointer { (buf: UnsafeBufferPointer<T>) in
                buffers.append(buf)
                recurse(body: body)
            }
        }
        
        recurse(body: body)
        
        return result!
    }
}

L'utilisation d'une fonction intégrée facilite l'écriture d'un processus qui combine ce type d'opération d'état et d'appel récursif. Je n'aime pas copier la valeur de retour autant de fois qu'il y a d'éléments, donc j'utilise ʻOptional et! `.

Maintenant, avec cela, vous pouvez appeler f0 comme suit.

let arr: Array<Array<CInt>> = [ [0, 1, 2], [3, 4, 5] ]
arr.withUnsafeBufferPointerArray { (bufPtrArr: Array<UnsafeBufferPointer<CInt>>) in
    let ptrArr: Array<UnsafePointer<CInt>?> = bufPtrArr.map { $0.baseAddress }
    f0(ptrArr)
}

À titre d'exemple pratique, OpenGL ES

void glShaderSource(
	GLuint shader,
	GLsizei count,
	const GLchar * const *string,
	const GLint *length);

Lorsqu'il est utilisé pour appeler

    public static func shaderSource(_ id: GLuint,
                                    _ strings: Array<Array<GLchar>>)
    {
        strings.withUnsafeBufferPointerArray { (buffers: Array<UnsafeBufferPointer<GLchar>>) in
            glShaderSource(id,
                           GLsizei(buffers.count),
                           buffers.map { $0.baseAddress },
                           buffers.map { GLint($0.count) })
        }
    }

C'est comme ça. C'est bien que les arguments count, string et length puissent tous être facilement construits à partir de buffers.

Recommended Posts

Convertir le tableau 2D de Swift en tableau 2D de C
Conversion du pointeur de chaîne de langage C en type Swift String
[Java] Convertir ArrayList en tableau
Passer le caractère de langage C * à Swift
Convertir l'alphabet en 26 base + environ la longueur du tableau
Convertir un tableau bidimensionnel au format csv avec l'API Java 8 Stream
[Java] Convertit un tableau en ArrayList * Attention
Convertir le langage C en JavaScript avec Emscripten
Convertir un tableau de chaînes en nombres
Convertit le tableau d'erreurs.full_messages en caractères et sortie
Comment convertir un fichier en tableau d'octets en Java
Générer des modèles de JSON à Swift, PHP, C #, JAVA
[Java] Je souhaite convertir un tableau d'octets en un nombre hexadécimal
Code du port C avec de nombreux typecasts vers Swift
Convertir un tableau d'octets Java en une chaîne hexadécimale
Convertir un tableau potentiellement nul en flux
Anything Arrangement-11 [Exemple de refactoring C #]
ABC --133- A & B & C & D
Je veux convertir des caractères ...
Convertir le type String en type Timestamp
Convertir en chaîne Ruby Leet
Convertir un objet sérialisable en octet []
ABC --122 --A & B & C & D
Conversion de ○ mois en ○ années ○ mois
ABC --125- A & B & C & D
ABC --130- A & B & C & D
ABC --126 --A & B & C & D
Comment initialiser un tableau Java
[Swift5] Comment obtenir un tableau et un ensemble de différences entre les tableaux