gpt4 book ai didi

来自 ArraySlice 的 Swift 指针

转载 作者:搜寻专家 更新时间:2023-10-31 19:30:23 24 4
gpt4 key购买 nike

我正在尝试确定创建我自己的连续内存容器的“Swift-y”方式(在我的特定情况下,我正在构建 n 维数组)。我希望我的容器在功能和可用性方面尽可能接近 Swift 的内置数组。


我需要访问指向我的容器内存的指针,以进行 Accelerate 和 BLAS 操作。

我想知道 ArraySlice 的指针是指向切片的第一个元素,还是指向其基址的第一个元素。

当我尝试测试 UnsafePointer<Int>(array) == UnsafePointer<Int>(array[1...2]) 时看起来 Swift 不允许从 ArraySlices 构造指针(或者我只是做错了)。

我正在寻找关于哪种方式最“Swift-y”的建议?


我知道在对数组进行切片时,以下内容是正确的:

let array = [1, 2, 3]
array[1] == array[1...2][1]

array[1...2][0] != 2 # index out of bounds error

换句话说,索引总是相对于基本数组执行的。

这表明:我们应该返回一个指向基的第一个元素的指针。因为切片是相对于它们的基数的。


但是,遍历切片(显然)只考虑该切片的元素:

for i in array[1..2] # i takes on 2 followed by 3

这表明:我们应该返回一个指向切片第一个元素的指针。因为切片有自己的起点。


如果我的用户想在 BLAS 操作中对切片进行操作,则可以直观地预期:

mmul(matrix1[1...2, 0...1].pointer, matrix2[4...5, 0...1].pointer)

指向 slice 的第一个元素,但我不知道这是否是 Swift ArraySlice 做事的方式。


我的问题:容器切片对象的指针应该指向切片的第一个元素,还是基础容器的第一个元素

最佳答案

这个操作是不安全的:

UnsafePointer<Int>(array)

你的意思是:

array.withUnsafeBufferPointer { ... }

这也适用于您的类型,并且是您应该用来与 BLAS 和 Accelerate 进行互操作的模式。你不应该尝试使用 pointer方法 IMO。

没有 promise array将在您实际访问指针时继续存在,即使这发生在同一行代码中。 ARC 可以自由地以惊人的速度摧毁那段内存。

UnsafeBufferPointer实际上是一个非常好的类型,因为它已经 promise 是连续的,并且它的行为就像一个集合。

我的建议是在内部管理您自己的内存,可能使用 ManagedBuffer , 但也许只是一个 UnsafeMutablePointer那你allocdestroy你自己。管理数据布局以使其与 Accelerate 兼容非常重要。你不想要 Array<Array<UInt8>> .那会增加太多的结构。您需要以良好的 C 方式(行*宽度+列等)索引到的字节 block 。您可能根本不希望切片直接返回指针。你的mmul函数可能需要特殊的逻辑来理解如何通过最少的复制将它需要的部分从切片中拉出来,以便它与 vDSP_mmul 一起工作。 . “通用”和“加速”很少一起出现。

例如,考虑到这一点:

mmul(matrix1[1...2, 0...1].pointer, matrix2[4...5, 0...1].pointer)

(显然,我假设您的真实矩阵要大得多;这种矩阵发送到 vDSP 没有多大意义。)

您将不得不编写自己的 mmul很明显,因为这个内存布局不正确。所以你不妨把切片传过去。然后你会做类似的事情(完全未经测试,未经编译,我确信语法是错误的):

mmul(m1: MatrixSlice, m2: MatrixSlice) -> Matrix {
var s1 = UnsafeMutablePointer<Float>.alloc(m1.rows * m1.columns)
// use vDSP_vgathr to copy each sliced row out of m1 into s1
var s2 = UnsafeMutablePointer<Float>.alloc(m2.rows * m2.columns)
// use vDSP_vgathr to copy each sliced row out of m2 into s2

var result = UnsafeMutablePointer<Float>.alloc(m1.rows * m2.columns)

vDSP_mmul(s1, 1, s2, 1, result, 1, m1.rows, m2.columns, m1.columns)
s1.destroy()
s2.destroy()

// This will need to call result.move() or moveInitializeFrom or something
return Matrix(result)
}

我只是在这里扔东西,但这可能是您想要的那种结构。

关于指向容器或数据的指针是否通常由 Swift 传递的基本问题,不幸的是,答案对于 Array 来说是“神奇的”,而不是其他任何人。将数组传递给需要指针的对象会神奇地(通过编译器,而不是标准库)将指针传递给数组的存储。没有其他类型的人有这种魔力。甚至没有ContiguousArray得到这个魔法。如果你传递一个 ContiguousArray对于需要指针的东西,您会将指针传递给容器(如果它是可变的,则破坏容器;真实​​的故事,讨厌那个……)

关于来自 ArraySlice 的 Swift 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34663500/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com