Conforming to AccelerateBuffer

Hello,

I'd like to perform some math on a fairly large number of CGPoint instances stored in an array so I thought I'd look into using Accelerate and start by conforming CGPoint to AccelerateBuffer, followed by extending Array to conform as well.

My problem is that I don't understand what to do with the requirement

Code Block Swift
public func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<CGFloat>) throws -> R) rethrows -> R

How am I supposed to implement this? Are there any code examples somewhere that I can look into?

Many thanks.

Accepted Reply

Follow-up...

After some more digging, and reading, and trial and error, I managed to get the implementation below, which I think is correct. However, now Xcode gives me a vDSP error that I don't understand, since CGPoint is now conforming to the types that vDSP expects its arguments and return values to have. What am I doing incorrectly?

(The code below is in a Playground)

Code Block swift
import Foundation
import CoreGraphics
import Accelerate
extension CGPoint: AccelerateMutableBuffer {
    public var count: Int { 2 }
    public func withUnsafeBufferPointer<R>(
_ body: (UnsafeBufferPointer<CGFloat>) throws -> R
) rethrows -> R {
        var varself = self
        let ubp = withUnsafeBytes(of: &varself) { urbp in
            urbp.bindMemory(to: CGFloat.self)
        }
        return try body(ubp)
    }
    public mutating func withUnsafeMutableBufferPointer<R>(
_ body: (inout UnsafeMutableBufferPointer<CGFloat>) throws -> R
) rethrows -> R {
        var varself = self
        var ubp = withUnsafeMutableBytes(of: &varself) { urbp in
            urbp.bindMemory(to: CGFloat.self)
        }
        return try body(&ubp)
    }
}
let p1 = CGPoint(x: 1.5, y: -3.5)
let p2 = CGPoint(x: -0.5, y: 2.5)
var p: CGPoint = .zero
vDSP.add(p1, p2, result: &p) // Error: "No exact matches in call to static method 'add(_:_:result:)'"
p


Replies

Follow-up...

After some more digging, and reading, and trial and error, I managed to get the implementation below, which I think is correct. However, now Xcode gives me a vDSP error that I don't understand, since CGPoint is now conforming to the types that vDSP expects its arguments and return values to have. What am I doing incorrectly?

(The code below is in a Playground)

Code Block swift
import Foundation
import CoreGraphics
import Accelerate
extension CGPoint: AccelerateMutableBuffer {
    public var count: Int { 2 }
    public func withUnsafeBufferPointer<R>(
_ body: (UnsafeBufferPointer<CGFloat>) throws -> R
) rethrows -> R {
        var varself = self
        let ubp = withUnsafeBytes(of: &varself) { urbp in
            urbp.bindMemory(to: CGFloat.self)
        }
        return try body(ubp)
    }
    public mutating func withUnsafeMutableBufferPointer<R>(
_ body: (inout UnsafeMutableBufferPointer<CGFloat>) throws -> R
) rethrows -> R {
        var varself = self
        var ubp = withUnsafeMutableBytes(of: &varself) { urbp in
            urbp.bindMemory(to: CGFloat.self)
        }
        return try body(&ubp)
    }
}
let p1 = CGPoint(x: 1.5, y: -3.5)
let p2 = CGPoint(x: -0.5, y: 2.5)
var p: CGPoint = .zero
vDSP.add(p1, p2, result: &p) // Error: "No exact matches in call to static method 'add(_:_:result:)'"
p


Doh! 🤦🏻‍♂️ I accidentally clicked on that checkmark button and now I can't uncheck it. This question is not yet resolved!
I understand the error message now. The Element type of the type conforming to Accelerate[Mutable]Buffer must be a Double. I can live with that since CGFloat is a Double on a 64-bit platform. Still, vDSP is not returning the correct result. Again, what am I doing incorrectly?

Many thanks.

Code Block swift
import Foundation
import CoreGraphics
import Accelerate
extension CGPoint: AccelerateMutableBuffer {
    public typealias Element = Double
    public var count: Int { 2 }
    public func withUnsafeBufferPointer <R> (
        _ body: (UnsafeBufferPointer<Element>) throws -> R
    ) rethrows -> R {
        var varself = self
        let ubp = withUnsafeBytes(of: &varself) { urbp in
            urbp.bindMemory(to: Element.self)
        }
        return try body(ubp)
    }
    public mutating func withUnsafeMutableBufferPointer <R> (
        _ body: (inout UnsafeMutableBufferPointer<Element>) throws -> R
    ) rethrows -> R {
        var varself = self
        var umbp = withUnsafeMutableBytes(of: &varself) { umrbp in
            umrbp.bindMemory(to: Element.self)
        }
        return try body(&umbp)
    }
}
let p1 = CGPoint(x: 1.5, y: 3.5)
let p2 = CGPoint(x: 0.5, y: 2.5)
var p: CGPoint = .zero
vDSP.add(p1, p2, result: &p)
p // result is (0.0, 0.0), not the expected (2.0, 6.0)


Edit: I've since figured it out. Here's the correct solution, as far as I know. It compiles without errors, runs without problems, and gives the correct result. So, unless someone sees a problem I'm not seeing, I'm now happy to consider this question resolved.

The problem with the previous implementation is on line 23: by creating a local mutable copy of self and operating on *that*, self itself doesn't get changed.

Code Block swift
import Foundation
import CoreGraphics
import Accelerate
extension CGPoint: AccelerateMutableBuffer {
public typealias Element = Double
public var count: Int { 2 }
public func withUnsafeBufferPointer<R>(_ body: (UnsafeBufferPointer<Double>) throws -> R) rethrows -> R {
try Swift.withUnsafeBytes(of: self) { urbp in
try body(urbp.bindMemory(to: Double.self))
}
}
public mutating func withUnsafeMutableBufferPointer <R> (
_ body: (inout UnsafeMutableBufferPointer<Double>) throws -> R
) rethrows -> R {
try Swift.withUnsafeMutableBytes(of: &self) { umrbp in
var umbp = umrbp.bindMemory(to: Double.self)
return try body(&umbp)
}
}
}
let p1 = CGPoint(x: 1.5, y: 3.5)
let p2 = CGPoint(x: 0.5, y: 2.5)
var p: CGPoint = .zero
vDSP.add(p1, p2, result: &p)
p // (x: 2, y: 6) ✅