Подтвердить что ты не робот

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

Я ищу простейшие способы достижения разумной совместимости С в 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), однако это не устраняет проблему самого цикла.

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

4b9b3361

Ответ 1

Вы можете просто инициализировать 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 Float из 12 байт, на которые указывает ptr.

Ответ 2

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)

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