$ 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
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
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