Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

I'm working with a C API from Swift and for one of the methods that I need to call I need to give a

UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>

More Info:

Swift Interface:

public func presage_predict(prsg: presage_t, _ result: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>) -> presage_error_code_t

Original C:

presage_error_code_t presage_predict(presage_t prsg, char*** result);
like image 425
Nykholas Avatar asked Sep 21 '15 05:09

Nykholas


2 Answers

There may be a better way but this runs in playground and defines a value r with the type you want:

func ptrFromAddress<T>(p:UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T>
{
   return p
}

var myInt:Int8 = 0
var p = ptrFromAddress(&myInt)
var q = ptrFromAddress(&p)
var r = ptrFromAddress(&q)

What's the point of defining ptrFromAddress, which seems like it does nothing? My thinking is that the section of the Swift interop book which discusses mutable pointers shows many ways to initialize them by passing some expression as an argument (like &x), but does not seem to show corresponding ways where you simply call UnsafeMutablePointer's initializer. So let's define a no-op function just to use those special initialization methods based on argument-passing

Update:

While I believe the method above is correct, it was pointed out by @alisoftware in another forum that this seems to be a safer and more idiomatic way to do the same thing:

var myInt: Int8 = 0
withUnsafeMutablePointer(&myInt) { (var p) in
  withUnsafeMutablePointer(&p) { (var pp) in
    withUnsafeMutablePointer(&pp) { (var ppp) in
      // Do stuff with ppp which is a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
    }
  }
}

It's more idiomatic because you're using the function withUnsafeMutablePointer which is supplied by the Swift standard library, rather than defining your own helper. It's safer because you are guaranteed that the UnsafeMutablePointer is only alive during the extent of the call to the closure (so long as the closure itself does not store the pointer).

like image 185
algal Avatar answered Nov 19 '22 05:11

algal


Generally, if a function takes a UnsafePointer<T> parameter then you can pass a variable of type T as in "inout" parameter with &. In your case, T is

UnsafeMutablePointer<UnsafeMutablePointer<Int8>>

which is the Swift mapping of char **. So you can call the C function as

var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK { ... }

From the documentation and sample code of the Presage library I understand that this allocates an array of strings and assigns the address of this array to the variable pointed to by prediction. To avoid a memory leak, these strings have to be released eventually with

presage_free_string_array(prediction)

To demonstrate that this actually works, I have taken the first part of the demo code at presage_c_demo.c and translated it to Swift:

// Duplicate the C strings to avoid premature deallocation:
let past = strdup("did you not sa")
let future = strdup("")

func get_past_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
    return UnsafePointer(past)
}

func get_future_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
    return UnsafePointer(future)
}

var prsg = presage_t()
presage_new(get_past_stream, nil, get_future_stream, nil, &prsg)

var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK {

    for var i = 0; prediction[i] != nil; i++ {
        // Convert C string to Swift `String`:
        let pred = String.fromCString(prediction[i])!
        print ("prediction[\(i)]: \(pred)")
    }

    presage_free_string_array(prediction)
}

free(past)
free(future)

This actually worked and produced the output

prediction[0]: say
prediction[1]: said
prediction[2]: savages
prediction[3]: saw
prediction[4]: sat
prediction[5]: same
like image 27
Martin R Avatar answered Nov 19 '22 04:11

Martin R