Приведение между типами массивов Swift без копирования или выделения - PullRequest
1 голос
/ 11 апреля 2019

Я хочу получить доступ к существующему массиву UInt64, как если бы это был массив Int8.Ключевым требованием является эффективность - я не хочу копировать или перераспределять данные, просто имею прямой доступ.Я не хочу побочных эффектов (например, я хочу продолжать использовать uint64Array после выполнения этого блока кода, читал о повторном связывании с неопределенными побочными эффектами.)

Я пытался сделать это сSwift 4.2:

var uint64Array = [UInt64](repeating: 0, count: 100)

uint64Array.withUnsafeMutableBufferPointer() {
    uint64Pointer in
    uint64Pointer.withMemoryRebound(to: Int8.self) {   // <- Error occurs here.
        int8Pointer in
        int8Pointer[0] = 1
        int8Pointer[1] = 2
        int8Pointer[2] = 3
        int8Pointer[3] = 4
    }
}

Однако я получаю фатальную ошибку во время выполнения в следующей строке:

    uint64Pointer.withMemoryRebound(to: Int8.self) {

Это правильный подход?Если да, то почему я получаю фатальную ошибку?

Ответы [ 2 ]

1 голос
/ 12 апреля 2019

Спасибо @brindy за решение этого вопроса.Вот реализация расширения, которая настолько чиста, насколько я мог бы ее получить.

Расширение:

extension Array {
    mutating func bindMutableMemoryTo<T,R>(_ type: T.Type, _ closure: (UnsafeMutableBufferPointer<T>) throws -> R) rethrows -> R {
        return try self.withUnsafeMutableBytes() {
            return try closure($0.bindMemory(to: type))
        }
    }
}

Использование:

   var uint64Array = [UInt64](repeating: 0, count: 100)
   uint64Array.bindMutableMemoryTo(Int8.self) {
        int8Pointer in
        int8Pointer[0] = 1 // LSB of uint64Array[0]
        int8Pointer[1] = 2
        int8Pointer[2] = 3
        int8Pointer[3] = 4 // MSB of uint64Array[0]
    }
1 голос
/ 11 апреля 2019

Я думаю, что проблема в том, что вы не можете напрямую связываться с другим типом согласно этой заметке в документации:

Используйте этот метод только для перепривязки памяти буфера к типу того же размера и шага, что и текущий связанный тип элемента. Чтобы связать область памяти с типом другого размера, преобразуйте буфер в необработанный буфер и используйте метод bindMemory (to :).

Если вы ищите байты, то самый быстрый маршрут:

var uint64Array = [UInt64](repeating: 0, count: 100)
uint64Array.withUnsafeMutableBytes { x in

    x[0] = 1
    x[1] = 2
    x[3] = 3
    x[4] = 4

}

Если у вас есть другой тип, который вы хотите использовать, вы можете сделать это следующим образом:

var uint64Array = [UInt64](repeating: 0, count: 100)

uint64Array.withUnsafeMutableBufferPointer() {
    uint64Pointer in

    let x = UnsafeMutableRawBufferPointer(uint64Pointer).bindMemory(to: Int32.self)
    x[0] = 1
    x[1] = 2
    x[3] = 3
    x[4] = 4

}
...