Search code examples
swiftpointersunsafe-pointers

Convert pointers from Swift 2 to Swift 3


How can I convert the following pointers initialization from Swift 2 to Swift 3?

var values: [Double]
...
var valuesAsComplex : UnsafeMutablePointer<DSPDoubleComplex>?
values.withUnsafeBufferPointer { (resultPointer: UnsafeBufferPointer<Double>) -> Void in
    valuesAsComplex = UnsafeMutablePointer<DSPDoubleComplex>( resultPointer.baseAddress )
}

Update: Thank your for all the answers. Permanently rebinding the pointer as @Aderstedt suggests works but returning the result doesn't. Any ideas?

// Create result
var result = [Double](repeating: 0.0, count: N/2)
var resultAsComplex : UnsafeMutablePointer<DSPDoubleComplex>?
result.withUnsafeMutableBytes {
    resultAsComplex = $0.baseAddress?.bindMemory(to: DSPDoubleComplex.self, capacity: result.count)
}

// Do complex->real inverse FFT.
vDSP_fft_zripD(fftSetup!, &tempSplitComplex, 1, LOG_N, FFTDirection(FFT_INVERSE));

// This leaves result in packed format. Here we unpack it into a real vector.
vDSP_ztocD(&tempSplitComplex, 1, resultAsComplex!, 2, N2);

// Neither the forward nor inverse FFT does any scaling. Here we compensate for that.
var scale : Double = 0.5/Double(N);
vDSP_vsmulD(&result, 1, &scale, &result, 1, vDSP_Length(N));

return result

Solution

  • You have to "rebind" the pointer:

    values.withUnsafeMutableBufferPointer {
        $0.baseAddress!.withMemoryRebound(to: DSPDoubleComplex.self, capacity: values.count/2) {
            valuesAsComplex in
    
            // ...
    
        }
    }
    

    Inside the closure valuesAsComplex is a UnsafeMutablePointer<DSPDoubleComplex> and can be passed to DSP functions.

    You must not pass the pointer to the element storage to the outside of the closure as the documentation clearly states:

    The pointer argument is valid only for the duration of the closure’s execution.

    That may work by chance, but there is no guarantee that after the execution of the closure, the elements storage is still at the same memory address (or that the array even exists, since the pointer is not a strong reference which ensures the lifetime of the storage).


    In your case that would be

        tempSplitComplex = DSPDoubleSplitComplex(realp: &mag, imagp: &phase)
        vDSP_ztocD(&tempSplitComplex, 1, &tempComplex, 2, N2);
    
        tempComplex.withUnsafeMutableBufferPointer {
            $0.baseAddress!.withMemoryRebound(to: Double.self, capacity: values.count * 2) {
                complexAsDouble in
    
                vDSP_rectD(complexAsDouble, 2, complexAsDouble, 2, N2);
            }
        }
    
        vDSP_ctozD(&tempComplex, 2, &tempSplitComplex, 1, N2);
    

    and

        var result = [Double](repeating: 0.0, count: N/2)
    
        result.withUnsafeMutableBufferPointer {
            $0.baseAddress!.withMemoryRebound(to: DSPDoubleComplex.self, capacity: result.count/2) {
                resultAsComplex in
    
                vDSP_ztocD(&tempSplitComplex, 1, resultAsComplex, 2, N2);
    
            }
        }