swiftaccelerate

How to safely call DSPSplitComplex without compiler warnings


I'm trying to call the function DSPSplitComplex:

var real = [Float](input_windowed)
var imaginary = [Float](repeating: 0.0, count: input_windowed.count)
        
var splitComplex = DSPSplitComplex(realp: &real, imagp: &imaginary)        

but that gives the warning:

Cannot use inout expression here; argument 'realp' must be a pointer that outlives the call to 'init(realp:imagp:)'

so after that I tried:

var splitComplex = DSPSplitComplex(
    realp:  UnsafeMutablePointer(mutating: real),
    imagp:  UnsafeMutablePointer(mutating: imaginary) )

and that gives the warning:

Initialization of 'UnsafeMutablePointer<Float>' results in a dangling pointer

so finally I tried this:

var splitComplex =
    withUnsafeMutablePointer(to: &real) { realpPtr in
        withUnsafeMutablePointer(to: &imaginary) { imaginaryPtr in
            DSPSplitComplex(realp: realpPtr, imagp: imaginaryPtr)
    }
}

and that gives the following compile error:

Cannot convert value of type 'UnsafeMutablePointer<[Float]>' to expected argument type 'UnsafeMutablePointer<Float>'

What is the correct way to call this function (and similar functions in the Accelerate framework) ?


Solution

  • You are very close. You just need a buffer pointer rather than a pointer to the array:

    real.withUnsafeMutableBufferPointer { realp in
        imaginary.withUnsafeMutableBufferPointer { imagp in
    
            var splitComplex = DSPSplitComplex(realp: realp.baseAddress!, 
                                               imagp: imagp.baseAddress!)
    
            // ...
        }
    }
    

    Note the BufferPointer part of the calls.

    For a full example, see Apple's FFT sample.

    The key point of this syntax rather than your original approach is that it ensures that real and imaginary continue to exist for the lifetime of the pointers. In your original code, the arrays can be deallocated on the very next line, making splitComplex hold dangling pointers.