I have a c_ptr
that points to a block of memory that I would like to treat as an array. I know its dimensions at runtime, but not at compile time. For the 1D case, I would like to have something like the following:
var size: c_int = getArraySizeFromCLibrary(...);
var ptr: c_ptr(c_double) = getArrayPtrFromCLibrary(...);
var myArray: [1..size] real = createArrayUsingPtr(ptr); // what do I do here?
Is it possible to do this or do I need to copy the data into the memory allocated for myArray?
I have checked the documentation for Arrays and for Chapel/C interop, but don't see any relevant functions. I have tried just assigning the ptr to the array in its initialization but get error: cannot iterate over values of type c_ptr(real(64))
.
I have a c_ptr
that points to a block of memory that I would like to treat as an array. I know its dimensions at runtime, but not at compile time. For the 1D case, I would like to have something like the following:
var size: c_int = getArraySizeFromCLibrary(...);
var ptr: c_ptr(c_double) = getArrayPtrFromCLibrary(...);
var myArray: [1..size] real = createArrayUsingPtr(ptr); // what do I do here?
Is it possible to do this or do I need to copy the data into the memory allocated for myArray?
I have checked the documentation for Arrays and for Chapel/C interop, but don't see any relevant functions. I have tried just assigning the ptr to the array in its initialization but get error: cannot iterate over values of type c_ptr(real(64))
.
I believe your search is correct in finding that Chapel doesn't have a documented library routine to do this today. It should, though, as requested in this GitHub issue, and I'd encourage readers wanting this capability to upvote or comment on that issue.
As noted on that issue (and a previous SO question), there is an undocumented routine that provides this capability with the following signatures:
proc makeArrayFromPtr(value: c_ptr, num_elts: uint) …
proc makeArrayFromPtr(value: c_ptr, dom: domain) …
The first of these will create a Chapel array with a 0-based low-bound (e.g., {0..<size}
) while the second will create an array with the specified domain, dom
. Note that these procedures should be considered unstable at present.
Here's an example, modeled on your question, of how this could be used to create an array with indices {1..size}
[ATO]:
var size: c_int = getArraySizeFromCLibrary();
var ptr: c_ptr(c_double) = getArrayPtrFromCLibrary();
var myArray = makeArrayFromPtr(ptr, {1..size});
The call could also be changed to:
var myArray = makeArrayFromPtr(ptr, size);
to get an array indexed via {0..<size}
[ATO], or to:
var myArray = makeArrayFromPtr(ptr, {1..3, 1..3});
to get a 2D array (assuming the pointer points to at least 9 valid elements) [ATO].
Note that in Chapel 2.3, I'm finding that this routine only works consistently for me if I use an inferred type for myArray
(as in the examples above), rather than declaring it with an explicit array type with an anonymous domain as in your question (var myArray: [1..size] real = …
). Using a named domain to both declare the array and pass to the routine also seems to work, though (e.g., var myArray: [dom] real = makeArrayFromPtr(ptr, dom);
[ATO]).
Here's a complete listing of the first of these three examples, for posterity:
// Here is your code, updated to use the undocumented routine
use CTypes, MyCLib;
var size: c_int = getArraySizeFromCLibrary();
var ptr: c_ptr(c_double) = getArrayPtrFromCLibrary();
var myArray = makeArrayFromPtr(ptr, {1..size});
// check that we've inherited the data properly
writeln(myArray, ": [", myArray.domain, "] ", myArray.eltType:string);
// check that modifying the C array is reflected in the Chapel array
c_arr[4] = -2.2;
writeln(myArray);
// and vice-versa (using 1-based indexing)
myArray[5] = -2.3;
writeln(c_arr);
module MyCLib { // This is a fake C library
use CTypes;
proc getArraySizeFromCLibrary() {
return 9:c_int;
}
var c_arr: c_array(c_double, 9);
c_arr[0] = 1.1;
c_arr[1] = 1.2;
c_arr[2] = 1.3;
c_arr[3] = 2.1;
c_arr[4] = 2.2;
c_arr[5] = 2.3;
c_arr[6] = 3.1;
c_arr[7] = 3.2;
c_arr[8] = 3.3;
proc getArrayPtrFromCLibrary() {
return c_ptrTo(c_arr[0]);
}
}