Преобразование UnsafePointer с длиной в тип Swift Array

Я ищу самые простые способы достижения разумной совместимости C в Swift, и мой текущий блок конвертирует UnsafePointer<Int8> (который был const char *), в [Int8] массив.

В настоящее время у меня есть наивный алгоритм, который может принять UnsafePointer и количество байтов и преобразует его в массив, элемент за элементом:

func convert(length: Int, data: UnsafePointer<Int8>) {

    let buffer = UnsafeBufferPointer(start: data, count: length);
    var arr: [Int8] = [Int8]()
    for (var i = 0; i < length; i++) {
        arr.append(buffer[i])
    }
}

Сам цикл может быть ускорен с помощью arr.reserveCapacity(length)Однако это не снимает проблему самого цикла.

Я знаю об этом так вопрос, который охватывает, как конвертировать UnsafePointer<Int8>в String, тем не мение String это другой зверь полностью [T], Есть ли удобный способ быстрого копирования байтов длины из UnsafePointer<T> в [T]? Я бы предпочел чистые методы Swift, не проходя через NSData или похожие. Если приведенный выше алгоритм действительно единственный способ сделать это, я буду рад этому.

3 ответа

Решение

Вы можете просто инициализировать Swift Array из UnsafeBufferPointer:

func convert(length: Int, data: UnsafePointer<Int8>) -> [Int8] {

    let buffer = UnsafeBufferPointer(start: data, count: length);
    return Array(buffer)
}

Это создает массив нужного размера и копирует данные.

Или как универсальная функция:

func convert<T>(count: Int, data: UnsafePointer<T>) -> [T] {

    let buffer = UnsafeBufferPointer(start: data, count: count);
    return Array(buffer) 
}

где length это количество элементов, на которые указывает указатель.

Если у тебя есть UInt8 указатель, но хочу создать [T] массив из указанных данных, тогда это возможное решение:

// Swift 2:
func convert<T>(length: Int, data: UnsafePointer<UInt8>, _: T.Type) -> [T] {

    let buffer = UnsafeBufferPointer<T>(start: UnsafePointer(data), count: length/strideof(T));
    return Array(buffer) 
}

// Swift 3:
func convert<T>(length: Int, data: UnsafePointer<UInt8>, _: T.Type) -> [T] {
    let numItems = length/MemoryLayout<T>.stride
    let buffer = data.withMemoryRebound(to: T.self, capacity: numItems) {
        UnsafeBufferPointer(start: $0, count: numItems)
    }
    return Array(buffer) 
}

где length сейчас число байтов. Пример:

let arr  = convert(12, data: ptr, Float.self)

создаст массив из 3 Floats из 12 байтов, на которые указывает ptr,

extension NSData {

    public func convertToBytes() -> [UInt8] {
        let count = self.length / sizeof(UInt8)
        var bytesArray = [UInt8](count: count, repeatedValue: 0)
        self.getBytes(&bytesArray, length:count * sizeof(UInt8))
        return bytesArray
    }
}

Вы можете преобразовать данные строки в байты (Uint8)

Скопируйте расширение и используйте его..

Вы также можете использовать функцию инициализации массива:

      init(unsafeUninitializedCapacity: Int, initializingWith initializer: (inout UnsafeMutableBufferPointer<Element>, inout Int) throws -> Void) rethrows

Сначала преобразуйте unsafeRawPointer в unsafePointer, если необходимо. Затем преобразуйте указатель в указатель буфера и, наконец, указатель буфера в массив.

Пример, если у вас есть unsafeRawPointer ( dataPtr) и его размер ( dataSize)

      let numberOfItems = dataSize / MemoryLayout<MyClass>.stride

let myArray = dataPtr.withMemoryRebound(to: MyClass.self,
                                        capacity: numberOfItems) { typedPtr in
    // Convert pointer to buffer pointer to access buffer via indices
    let bufferPointer = UnsafeBufferPointer(start: typedPtr, count: numberOfItems)
    // Construct array
    return [MyClass](unsafeUninitializedCapacity: numberOfItems) { arrayBuffer, count in
        count = numberOfItems
        for i in 0..<count {
            arrayBuffer[i] = bufferPointer[i]
        }
    }
}
Другие вопросы по тегам