Conforming CGPoint to AccelerateMutableBuffer to use vDSP

121 Views Asked by At

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 AccelerateMutableBuffer, followed by extending Array to conform as well.

After some trial and error, I came up with the following, which compiles without any errors, but the result returned by vDSP.add(_:, _:, result:) is not correct: the variable p is still .zero at the end.

What am I missing?

Many thanks.

(You can try the code below on a Playground)

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

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 happy with considering this question resolved.

The problem with the previous implementation is that, in creating a local mutable copy of self (var varself = self) and operating on that, self itself doesn't get changed.

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)  ✅
0

There are 0 best solutions below