Я изучал возможные варианты использования UnsafePointer и связанных с ним UnsafeX в Swift, и мне интересно, что это за вариант использования i Swift. Похоже, что основным вариантом использования является производительность, но в то же время типы должны обеспечивать оптимизацию компилятора и производительность, поэтому я не уверен, когда они действительно полезны. Я хотел бы знать, могут ли все вещи быть реорганизованы, чтобы не использовать их с одинаковой или лучшей производительностью, или, если нет, какой конкретный пример с описанием кода и, возможно, некоторого кода или псевдокода, который демонстрирует, как он предлагает преимущество в производительности. Мне бы хотелось получить ссылку на конкретный пример, демонстрирующий преимущество в производительности из-за небезопасных указателей и небезопасных вещей.
Некоторые вещи, которые я нашел, связанные со Swift:
Однако UnsafePointer является важным API для взаимодействия и построения высокопроизводительных структур данных. - http://atrick.github.io/proposal/voidpointer.html
Но типизация позволяет оптимизировать компилятор. Мне интересно, какие преимущества дает использование небезопасных функций.
В некоторых местах вы видите использование этого в коде Metal, например здесь :
// Create buffers used in the shader
guard let uniformBuffer = device.makeBuffer(length: MemoryLayout<Uniforms>.stride) else { throw Error.failedToCreateMetalBuffer(device: device) }
uniformBuffer.label = "me.dehesa.metal.buffers.uniform"
uniformBuffer.contents().bindMemory(to: Uniforms.self, capacity: 1)
// or here
let ptr = uniformsBuffer.contents().assumingMemoryBound(to: Uniforms.self)
ptr.pointee = Uniforms(modelViewProjectionMatrix: modelViewProjectionMatrix, modelViewMatrix: modelViewMatrix, normalMatrix: normalMatrix)
Я пока не очень хорошо понимаю, что происходит с указателями, но я хотел спросить, предлагают ли эти варианты использования повышение производительности или их можно было бы реорганизовать, чтобы использовать безопасную версию, имеющую аналогичную или даже лучшую производительность.
увидел здесь тоже:
func setBit(_ index: Int, value: Bool, pointer: UnsafeMutablePointer<UInt8>) {
let bit: UInt8 = value ? 0xFF : 0
pointer.pointee ^= (bit ^ pointer.pointee) & (1 << UInt8(index))
}
Больше металла :
uniforms = UnsafeMutableRawPointer(uniformBuffer.contents()).bindMemory(to:GUniforms.self, capacity:1)
vertexBuffer = device?.makeBuffer(length: 3 * MemoryLayout<GVertex>.stride * 6, options: .cpuCacheModeWriteCombined)
vertices = UnsafeMutableRawPointer(vertexBuffer!.contents()).bindMemory(to:GVertex.self, capacity:3)
vertexBuffer1 = device?.makeBuffer(length: maxCount * maxCount * MemoryLayout<GVertex>.stride * 4, options: .cpuCacheModeWriteCombined)
vertices1 = UnsafeMutableRawPointer(vertexBuffer1!.contents()).bindMemory(to:GVertex.self, capacity: maxCount * maxCount * 4)
Материал относительно изображений:
func mapIndicesRgba(_ imageIndices: Data, size: Size2<Int>) -> Data {
let palette = self
var pixelData = Data(count: size.area * 4)
pixelData.withUnsafeMutableBytes() { (pixels: UnsafeMutablePointer<UInt8>) in
imageIndices.withUnsafeBytes { (indices: UnsafePointer<UInt8>) in
var pixel = pixels
var raw = indices
for _ in 0..<(size.width * size.height) {
let colorIndex = raw.pointee
pixel[0] = palette[colorIndex].red
pixel[1] = palette[colorIndex].green
pixel[2] = palette[colorIndex].blue
pixel[3] = palette[colorIndex].alpha
pixel += 4
raw += 1
}
}
}
return pixelData
}
Материал относительно входных потоков:
fileprivate extension InputStream {
fileprivate func loadData(sizeHint: UInt) throws -> Data {
let hint = sizeHint == 0 ? BUFFER_SIZE : Int(sizeHint)
var buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: hint)
var totalBytesRead = read(buffer, maxLength: hint)
while hasBytesAvailable {
let newSize = totalBytesRead * 3 / 2
// Ehhhh, Swift Foundation's Data doesnt have `increaseLength(by:)` method anymore
// That is why we have to go the `realloc` way... :(
buffer = unsafeBitCast(realloc(buffer, MemoryLayout<UInt8>.size * newSize), to: UnsafeMutablePointer<UInt8>.self)
totalBytesRead += read(buffer.advanced(by: totalBytesRead), maxLength: newSize - totalBytesRead)
}
if streamStatus == .error {
throw streamError!
}
// FIXME: Probably should use Data(bytesNoCopy: .. ) instead, but will it deallocate the tail of not used buffer?
// leak check must be done
let retVal = Data(bytes: buffer, count: totalBytesRead)
free(buffer)
return retVal
}
}