1

I have an array of float value (floatArray) coming from HDF5 file, and I'd like to use this data as an input for the function that accepts Unsafe[Mutable]Pointer (inputForFunction). I'm new to UnsafePointer, so I need someone's help.

One way I have in mind is, to store the array to a file, then to open it and to map the file descriptor to the memory of the variable for the input of the function:

  // read the data from HDF5 file
  var floatArray: [Float] = try originalHDF5DataSet.read()

  // store the data
  let dataToStore = NSData(bytes: &floatArray, length: sizeOfArray * MemoryLayout<Float>.size)
  let tmpPath = URL(fileURLWithPath: NSTemporaryDirectory())
  let filePath = tmpPath.appendingPathComponent("floatArrayData").appendingPathExtension("dat")
  do{
    try data.write(to: filePath, options: .atomic)
    let fileManager : FileManager   = FileManager.default
    if fileManager.fileExists(atPath:filePath.path){
      print("Success")
    }else{
      print("Fail")
    }

    // open the data 
    let dataPath = filePath.path
    let fd = open(dataPath, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
    assert(fd != -1, "Error: failed to open output file at \""+dataPath+"\"  errno = \(errno)\n")
    // memory map the parameters
    let hdr = mmap(nil, Int(sizeOfArray), PROT_READ, MAP_FILE | MAP_SHARED, fd, 0)
    // cast Void pointers to Float
    let inputForFunction = UnsafePointer<Float>(hdr!.assumingMemoryBound(to: Float.self))
  } catch{
    print("failed")
  }

However, it may not be the best implementation because the process to store the data seems time-consuming.

That's why I'm considering to use UnsafePointer to pass the pointer from floatArray to inputForFunction, but I'm not sure how to implement it. Just for your information, one way I'm thinking of is to use withUnsafePointermethod directly:

var floatArray: [Float] = try originalHDF5DataSet.read()
var inputForFunction = UnsafeMutablePointer<Float>.allocate(capacity: Int(sizeOfArray))
withUnsafePointer(to: &floatArray[0]) { (ptr: UnsafePointer<Float>) in
  inputForFunction = UnsafeMutablePointer(mutating: ptr)
}

or the other way is to use withMemoryRebound (but the following didn't work):

var floatArray: [Float] = try originalHDF5DataSet.read()
var inputForFunction = UnsafeMutablePointer<Float>.allocate(capacity: Int(sizeOfArray))
withUnsafePointer(to: &floatArray) { (ptrDataArray: UnsafePointer<[Float]>) in
  inputForFunction = ptrDataArray.withMemoryRebound(to: inputForFunction.self, capacity: Int(sizeOfArray), { (ptr: UnsafePointer<[Float]>) -> UnsafeMutablePointer<Float> in
    return ptr[0]
  })
}

My question is

  • How to pass the address of floatArray's data to inputForFunction?
  • If I need to convert from UnsafePointer<[Float]> to Unsafe[Mutable]Pointer, how to do it?
  • If needed, how to use withMemoryRebound for this purpose? Can I assign the address/value to inputForFunction inside the closure?
  • When I checked the addresses of floatArray and floatArray[0], they were different (This seems different from C/C++). Which address should be passed to inputForFunction?
kangaroo
  • 407
  • 4
  • 19
  • How *exactly* is the function declared to which you want to pass the data? – Martin R Dec 01 '16 at 09:21
  • This is for a CNN on iOS. input is for kernelWeights and bias. init(device: MTLDevice, convolutionDescriptor fullyConnectedDescriptor: MPSCNNConvolutionDescriptor, kernelWeights: UnsafePointer, biasTerms: UnsafePointer?, flags: MPSCNNConvolutionFlags) – kangaroo Dec 01 '16 at 20:13

2 Answers2

2

You can find many articles explaining how you can get Unsafe(Mutable)Pointer<Float> from [Float]. Some of them answer some of your questions. Try find them later.

  • How to pass the address of floatArray's data to inputForFunction?

    You usually use the Array's methods withUnsafeBufferPointer or withUnsafeMutableBufferPointer. You can get an Unsafe(Mutable)BufferPointer<Element> inside the closure parameter, which contains an Unsafe(Mutable)Pointer<Element> as its baseAddress property.

    var floatArray: [Float] = try originalHDF5DataSet.read()
    floatArray.withUnsafeBufferPointer {unsafeBufferPointer in
        let inputForFunction = unsafeBufferPointer.baseAddress
        //`unsafeBufferPointer` (including its `baseAddress`) is valid only in this closure.
        //So, do not pass `inputForFunction` outside of the closure, use it inside.
        //...
    }
    
  • If I need to convert from UnsafePointer<[Float]> to Unsafe[Mutable]Pointer, how to do it?

    When you find something like UnsafePointer<[Float]>, then you are going the wrong way. In Swift, Array is a hidden struct which may contain (multi-level) indirect reference to its elements. You usually have no need to use UnsafePointer<Array<Float>>.

  • If needed, how to use withMemoryRebound for this purpose? Can I assign the address/value to inputForFunction inside the closure?

    When you have an Array of AType and want to pass it as an Unsafe(Mutable)Pointer<AnotherType>, you may utilize withMemoryRebound. But in your case, you only need to work with Float, so withMemoryRebound may not be needed for your purpose.

  • When I checked the addresses of floatArray and floatArray[0], they were different (This seems different from C/C++). Which address should be passed to inputForFunction?

    None. As I wrote above, address of floatArray is just pointing somewhere which contains a hidden struct, so it's completely useless for your purpose. And address of floatArray[0] is neither guaranteed to be the address of the first element of the whole content. Swift may create a temporal region which contains only one element, and passing the address of the temporal region.


By the way, do you really need to convert your [Float] to Unsafe(Mutable)Pointer<Float>?

If your functions' signature is something like this:

func takingUnsafePointer(_ pointer: UnsafePointer<Float>)

You can call it like:

takingUnsafePointer(floatArray)
//In this case `floatArray` can be a `let` constant.

Or else, if the function signature is:

func takingUnsafeMutablePointer(_ pointer: UnsafeMutablePointer<Float>)

Call it as:

takingUnsafeMutablePointer(&floatArray)
//In this case `floatArray` needs to be a `var`, not `let`.

Remember, in both cases, the passed pointer is valid only while the function call. You should not export the pointer somewhere else.

OOPer
  • 47,149
  • 6
  • 107
  • 142
  • Maybe I don't need to convert. If I pass `floatArray` as an argument, does this mean to pass the address of the array as a let constant? – kangaroo Dec 01 '16 at 20:17
  • 1
    @kazoo, I think I can say yes. Check [this part](https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/doc/uid/TP40014216-CH8-ID23) of the [Using book](https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216). Even an Array literal can be passed to const pointer argument of C-function. – OOPer Dec 02 '16 at 00:08
  • I got it for that part. I'm still not sure about the difference to pass baseAddress and floatArray. I printed the actual value of the address and found that they were different (Also, baseAddress and the address of floatArray[0] were same.). As you mentioned, floatArray is pointing to somewhere with a hidden struct. If so, is it possible to pass whole the floatArray's data to the function by passing `floatArray`? Should I use baseAddress instead? Or are both completely same? – kangaroo Dec 02 '16 at 01:08
  • 1
    @kazoo, in Swift, when passing an array to a pointer argument, Swift may copy the whole content of the array to a temporal region and the address of the region is passed. The same may happen when creating a bufferPointer which may contain a temporal region of the array as its `baseAddress`. This may not happen always, so the address may be the same in some cases, may be different in other cases. One thing sure is that the region is kept while executing the function or the closure. Unless your function requires the same address over different function calls, both work well. – OOPer Dec 02 '16 at 01:32
1

Array type have withUnsafeBufferPointer method.

This method accept closure with UnsafeBufferPointer which is like UnsafePointer<[Float]> you're asking for.

In you need UnsafePointer to the start of Array you can use baseAddress property of UnsafeBufferPointer.

Example code:

let bufferPointer: UnsafeBufferPointer<Float> = floatArray.withUnsafeBufferPointer { bufferPointer in
    return bufferPointer
}

or

let baseAddress: UnsafePointer<Float> = floatArray.withUnsafeBufferPointer { bufferPointer in
    return bufferPointer.baseAddress
}

EDIT: Or if it's function just passing &floatArray may work.

user28434'mstep
  • 6,290
  • 2
  • 20
  • 35
  • 1
    Apple's [API Reference of `withUnsafeBufferPointer`](https://developer.apple.com/reference/swift/contiguousarray/1538290-withunsafebufferpointer) clearly states that **The pointer argument is valid only for the duration of the closure’s execution.** You'd better not export the `bufferPointer` or its `baseAddress` outside of the closure. Unfortunately, your code may work in some limited conditions, but the conditions are not specified. You should avoid such risky usage. – OOPer Dec 01 '16 at 10:04
  • @OOPer, well it is `Unsafe`. And yeah, I think passing `&floatArray` in func may be enough to solve Op's problem. – user28434'mstep Dec 01 '16 at 10:44
  • _I think passing `&floatArray` in func may be enough to solve Op's problem._ I agree. Your **EDIT** may be the best solution for OP. So, I added the latter part into my answer. – OOPer Dec 01 '16 at 11:08