Преобразование 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 Float
s из 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]
}
}
}