juppy
juppy

Reputation: 155

Receiving multidimensional array from C api, how to handle in Swift?

I use a C library in my Swift application and I cannot figure out how to get the multidimensional array that the C method is supposed to return.

I receive this from the C API:

struct resultArray
{
    double *data;
    int size[2];
};

Where:

size = the matrix size, a two element array with the number of rows and number of columns

data = the matrix data

In swift I can do the following to get the size:

let numRows = Int(results.size.0)
let numColoumns = Int(results.size.1)

But I don't understand how to get the matrix so that I can iterate through it? I tried the following:

let matrixResult = results.data.memory

This seems to return only a double value because matrixResult becomes a Double.

Then I tried this:

let matrixResult = results.data

Which makes the matrixResult an:

UnsafeMutablePointer<Double>

I expect to receive a matrix as specified in the C library documentation. Then I want to iterate through this matrix and get the values from the first row and put it in a Swift array... Does somebody know what I am missing here?

Upvotes: 6

Views: 378

Answers (2)

Martin R
Martin R

Reputation: 540145

There is no matrix type in C. Assuming that data is a pointer to the contiguous matrix elements stored as an array, you would copy the first row to a Swift array with

let firstRow = Array(UnsafeBufferPointer(start: results.data, count: numColumns))

and the entire "matrix" to a nested Swift array with

let matrix = (0 ..< numRows).map { row in
    Array(UnsafeBufferPointer(start: results.data + numColumns * row, count: numColumns))
}

Alternatively (and this is similar to what Melifaro suggested), you can create an array of pointers pointing into the matrix rows:

let matrix = (0 ..< numRows).map { row in
    UnsafeBufferPointer(start: results.data + numColumns * row, count: numColumns)
}

This still allows to address arbitrary elements in a matrix-like fashion

 let element = matrix[row][col]

but does not copy the data. Of course this requires that the matrix data is valid throughout the use of matrix, as the memory is not managed by Swift.

Upvotes: 4

Igor B.
Igor B.

Reputation: 2229

BTW, If you work with huge data set, it makes sense to deal with data in the C-Structure directly, instead of duplicating it in Swift data structure. So one another way to do the same:

let (I, J) = res.size

for i in 0..<I {
    for j in 0..<J {
        let v = res.data.advancedBy(Int(j + i * J))
        let d: Double = v.memory
        print("[\(i), \(j)]: \(d)")
    }
}

Upvotes: 3

Related Questions