Swift buffer pointer & array indexing

1k views Asked by At

I have the following code:

 public struct HistogramData {
   var red:[vImagePixelCount] = []
   var green:[vImagePixelCount] = []
   var blue: [vImagePixelCount] = []
   var alpha: [vImagePixelCount] = []
 }

And then I was accessing it as follows:

     var data: HistogramData
     ...

     let red:UnsafeMutablePointer<vImagePixelCount> =  UnsafeMutablePointer(mutating: data.red)
      let green:UnsafeMutablePointer<vImagePixelCount> = UnsafeMutablePointer(mutating: data.green)
      let blue:UnsafeMutablePointer<vImagePixelCount> = UnsafeMutablePointer(mutating: data.blue)

The above lines were incorrect and XCode showed a warning of dangling pointers. So I modified the code as:

  data.red.withUnsafeMutableBufferPointer { redPtr in
            data.green.withUnsafeMutableBufferPointer { greenPtr in
                data.blue.withUnsafeMutableBufferPointer { bluePtr in
                    
                    let red = redPtr.baseAddress!
                    let green = greenPtr.baseAddress!
                    let blue = bluePtr.baseAddress!
                    
                    for i in 0..<256 {
                        if red[i] > maxR {
                            maxR = red[i]
                        }
                        
                        if green[i] > maxG {
                            maxG = green[i]
                        }
                        
                        if blue[i] > maxB {
                            maxB = blue[i]
                        }
                    }

               ...
         }

Even though the above code works, but I am not really sure we can use array indices on baseAddress in Swift. The right way may be to bind memory to certain size, but when the size of array is not specified, how does bindMemory work? How do I fix the above code if it is wrong (even though it may work, it may not be right)?

1

There are 1 answers

0
Martin R On BEST ANSWER

Your code is correct.

someArray.withUnsafeMutableBufferPointer { bufPtr in ... }

calls the closure with an UnsafeMutableBufferPointer referencing the array's (mutable) element storage and is already bound to the element's type. Rebinding would only be necessary if you want to access the memory as a different type.

Then both bufPtr[i] and bufPtr.baseAddress![i] access the i-th array element (via the subscript method of UnsafeMutableBufferPointer resp. UnsafeMutablePointer). The only difference is that the former does a bounds check on the index in debug mode.

In optimized code, both subscript methods access the element storage without a bounds check. That can be a method improve the performance (at the cost of safety).

I suggest to benchmark if this part of your code is performance critical, and if the unsafe access is really faster than the “normal” array access.