Best way to wrap a C array pointer as a Chapel array - chapel

When interoperating with C, I often find myself being handed a pointer to an array. Chapel currently lets me treat this pointer as a 1D 0-indexed array. However, there are cases where I'd like to treat this pointer as a Chapel array (with eg. a multidimensional domain). What would the most idiomatic way to achieve this in Chapel?
I might have tried to do this by wrapping the C pointer in a class (with a domain) and defining this, and these (serial and parallel) methods so that one could index into and iterate over the class. In order to implement this, it would be useful to have a function that maps an index in a domain to a 0-indexed location. Is there such a built in function?

Unfortunately there does not appear to be a function that works for every domain. DefaultRectangularArr uses a method called getDataIndex under the covers that performs this computation, and it looks like other array types rely on a similar method defined on an inner storage class. It looks like these are not available on the domains themselves. I suspect relying on any of these would be inadvisable as they may be changed as part of an implementation adjustment, anyways.
Our hope is that eventually pointers like what you are describing could be wrapped in Chapel arrays using something like the makeArrayFromPtr function defined for interoperability. Unfortunately this function only supports 1D 0-indexed arrays today, but work is currently being done to expand our support for array interoperability. I would expect that function to adjust its arguments or for another version to be defined for multi-dimensional arrays, and we are still figuring that out.

I was curious whether I could trick a Chapel array into referring to a buffer allocated in C without much effort. I was able to do it, but am not proud of the result. Specifically:
it uses features that aren't user-facing, so may change or break at any future point
it currently only works for rectangular Chapel arrays that start indexing at 0 in each dimension
With those caveats in mind, here's a simple C header that exposes a few simple routines to be called from Chapel. The first allocates a trivial 9-element array; the second frees its argument.
#include <stdlib.h>
double* getDataPtr() {
double* dataPtr = (double*)malloc(9*sizeof(double));
dataPtr[0] = 1.1;
dataPtr[1] = 1.2;
dataPtr[2] = 1.3;
dataPtr[3] = 2.1;
dataPtr[4] = 2.2;
dataPtr[5] = 2.3;
dataPtr[6] = 3.1;
dataPtr[7] = 3.2;
dataPtr[8] = 3.3;
return dataPtr;
}
void freeDataPtr(double* ptr) {
free(ptr);
}
and here's the Chapel code that calls into it, then forces the C pointer into an existing array of the appropriate size and 0-based indices:
//
// Declare a Chapel array. Note that this program will only work as
// written if it uses 0-based indexing.
//
var A: [0..2, 0..2] real;
//
// testit.h is the C code above. It defines a simple C stub that returns a pointer
// to floating point data.
//
require "testit.h";
//
// Here are the key routines that testit.h exposes back to Chapel to
// get and free a pointer to floating point data.
//
extern proc getDataPtr(): c_ptr(real);
extern proc freeDataPtr(ptr: c_ptr(real));
//
// Grab the pointer from C
//
const myCPtr = getDataPtr();
//
// Save two pointer values defined in A's descriptor. Note that these
// are not part of its public interface, so are not recommended for
// typical users and could change / break at any future point.
//
const saveData = A._value.data;
const saveShiftedData = A._value.shiftedData;
//
// Replace these pointers with the one we got from C.
//
A._value.data = (myCPtr: _ddata(real));
A._value.shiftedData = (myCPtr: _ddata(real));
//
// print out A, "proving" that we're referring to the data from C
//
writeln(A);
//
// restore the original pointers to avoid having Chapel try to free
// the C memory / leak the Chapel memory.
//
A._value.data = saveData;
A._value.shiftedData = saveShiftedData;
//
// Free the C data
//
freeDataPtr(myCPtr);
The output of Chapel's writeln(A) statement is:
1.1 1.2 1.3
2.1 2.2 2.3
3.1 3.2 3.3
I think it'd be completely reasonable to file a feature request on Chapel's GitHub issues page proposing a better user-facing interface for adopting a C pointer like this, albeit in a nicer and more official way.

A slightly different approach might be below. The downside here is that this isn't a Chapel array, but it does allow for indexing/iterating just like a Chapel array would. This doesn't handle strides or non-zero alignments and there is no bounds-checking done.
prototype module CPtrArray {
use SysCTypes;
record CPtrArray {
type eltType;
param rank : int;
const first : rank*int;
const blk : rank*int;
var data : c_ptr(eltType);
proc init(type t, D : domain, ptr : c_ptr(t)) {
this.eltType = t;
this.rank = D.rank;
this.first = D.first;
var blktmp : rank*int;
blktmp(rank) = 1;
if (rank > 1) {
for param idim in (rank-1)..1 by -1 {
blktmp(idim) = blktmp(idim+1)*D.shape(idim+1);
}
}
this.blk = blktmp;
this.complete();
data = ptr;
}
proc getDataOffset(ndx : rank*int) : int {
var offset = ndx(rank)-first(rank);
if (rank > 1) {
for param idim in 1..(rank-1) do
offset += (ndx(idim)-first(idim))*blk(idim);
}
return offset;
}
inline proc this(ndx : rank*int) ref {
return data[getDataOffset(ndx)];
}
inline proc this(i:int ...rank) ref {
return this(i);
}
// Should provide iterators as well.
}
}
A simple test program that uses it :
use CPtrArray;
var A : [0.. #10] real;
forall ii in 0.. #10 do A[ii] = ii+1.0;
writeln(A);
var ptr = c_ptrTo(A[0]);
// Code for testing the array class goes here
const D = {1.. #5, 3.. #2};
var A1 = new CPtrArray(real, D, ptr);
for ndx in D {
writeln(ndx," ",A1[ndx]);
}

Related

How to copy the data of an array of pointers in C++

I'm trying to copy the data present in an array of pointers to another one.
I have very few knowledge in C++, but some in higher level languages.
Here is a sample code of what I've achieved so far (simplified version):
#define MAX_ACTIVE_MODES 3
myStruct_t priorities1[MAX_ACTIVE_MODES];
myStruct_t *priorities2[MAX_ACTIVE_MODES];
for (unsigned short i = 0; i < MAX_ACTIVE_MODES; ++i) {
priorities2[i] = (myStruct_t*)malloc(sizeof(myStruct_t));
memcpy(priorities2[i], &priorities1[i], sizeof(myStruct_t));
}
// ...
delete[] *priorities2;
It's easier for me to have a non pointer var for priorities1 and have one for priorities2 because I'm passing it to a sort function.
When I search for solutions, there's never the case of type *var[] and I don't get why.
Even though your question is tagged c++, I assume that you are programming in C based on your use of malloc.
First you don't need to use memcpy to copy structs.
*priorities2[i] = priorities1[i];
should be equivalent to
memcpy(priorities2[i], &priorities1[i], sizeof(myStruct_t));
Second, you don't have to create copies of the elements in priorities1[]. Just have the pointers in priorities2[] point to the elements in priorities1[]:
for (size_t i = 0; i < MAX_ACTIVE_MODES; ++i)
{
priorities2[i] = &priorities1[i];
}
As long as you don't access priorities2 beyond the lifetime of priorities1, no malloc or free is needed.

c++ function returns array with offset

I am working with some C code (not my own) that interfaces with Fortran and insists that all arrays be 1-based. I have a method that returns (a pointer to) an array that I have to line up correctly. The following works:
double* a;
...
a = returnedArray(arraySize);
Now what I need is to get the return to align at a[1], a[2], ... instead. (Of course I could shift things around manually, but there has to be a better way.) I tried to get the compiler to accept
a[1] = returnedArray(arraySize);
*(a+1) = ...
and several other permutations, without success. A web search has not given me anything useful, either.
Try:
`a=returnedArray(arraySize)-1;`
You cannot change that fact that returnedArray() returns a pointer to the first element of your array. And in C arrays, the first element is inevitably index 0.
However, if you offset the pointer by one element before using it, maybe you'll achieve your goal?
double * a;
...
a = returnedArray(arraySize) - 1;
...
double firstValue = a[1];
However, I strongly suggest you stick with index 0 being the first element, and fix the interfacing with Fortran in some other way. Surely, at some point you'll introduce a hard-to-find bug if you keep mixing 0-based and 1-based arrays in your code.
You want to do something like that ?
the array a start at tab[1]
double tab[10];
for(int i = 0 ; i < 10 ; i++){
tab[i] = i;
}
double *a = &tab[1];
for(int i =0 ; i < 9 ; i++){
cout << a[i] << endl;
}
If the memory between Fortran and C is being shared (eg. not copied), you cannot change the indexing of the built-in C type yourself. However, you could make a wrapper for your arrays returned from Fortran, which would make accessing them more convenient, and make it quite clear the difference between 1-indexing and 0-indexing. For example:
class FortranArrayWrapper
{
public:
FortranArrayWrapper(double* a) : A(a) { }
operator double* () const
{
return &A[1];
}
double* A;
};
FortranArrayWrapper a(returnedArray(arraySize));
a[0] = ...; // Index 1 in the array returnedArray, ie. first element in the Fortran array.
a.A[0] = ...; // Actually index '0', unused by Fortran.

passing a multidimensional array to a function with argument of type double *

I am using a library that takes a pointer to a double array as an argument, called as follows:
const int N=10;
const int J=20;
double my_array[N*J];
libFunc(my_array, N, J);
I would prefer to work with multidimensional arrays in my code, and I have discovered that I can call libFunc by dereferencing my multidimensional double array as follows
double my_array2[N][J];
libFunc(&my_array2[0][0], N, J);
However, I am worried that this code might not be portable, that it may not continue to work as N and M get large, and that there may be other hidden problems.
Why is this bad, what should I look out for here? What is the proper way to use multidimensional arrays and pass them to libFunc as if they were ordinary double arrays?
Edit: Read the comments below the selected answer for a discussion of the issue at hand. It seems that if I declare a static array, as is done above, then this code should work on most compilers. However if the array is dynamically allocated there may be an issue.
There is no simple way short of making a copy. Accessing an array outside its bounds is undefined behaviour, and you won't get around this.
Now, it is possible in many situations that your code works, simply because the memory for T[M * N] and for T[M][N] is laid out in the same way. As long as the caller and the callee aren't visible to the compiler at the same time, I would hazard a guess that this should work.
But imagine this scenario:
T a[M][N];
for (size_t i = 0; i != M * N; ++i)
{
a[0][i] = 0;
}
Here the compiler may reason that a[0][N] is out of bounds, and thus there is undefined behaviour, and the compiler may legally omit the entire loop, or make the application crash or wipe your hard disk.
So... take your pick. Undefined behaviour is around somewhere, but you might get lucky.
You are basically screwed: The function expects a double *, so you should give it a double *.
The easiest and safer way to do that would be to use a wrapper. Something like:
template<size_t M, size_t N>
class Double2DArray
{
std::vector<double> m_container ; // It could be a double[M * N]
// But it could explode your stack
// So let's use the heap
public :
// Etc.
Double2DArray()
: m_container(M * N)
{
// I assume the default you want is a vector already
// filled with 0.0
}
size_t getSizeM() { return M ; }
size_t getSizeN() { return N ; }
double & operator() (size_t p_m, size_t p_n)
{
return m_container[p_m * N + p_n] ;
}
double * data()
{
return &(m_container[0]) ;
}
// etc.
} ;
Of course, this code is not complete: At the very least, you should add the const versions of the accessors, probably handle copy-construction and assignment, etc.. I don't know your exact needs, so, your mileage may vary, but the core idea is there...
You could use this wrapper as follow:
void foo()
{
Double2DArray<42, 13> my2DArray ;
// etc.
my2DArray(3, 5) = 3.1415 ; // set some value
double d = my2DArray(13, 2) ; // get some value
// etc.
libFunc(my2DArray.data(), my2DArray.getSizeM(), my2DArray.getSizeN());
}
I would even overload libFunc to be safer:
template<size_t M, size_t N>
inline void libFunc(Double2DArray<M, N> & p_my2DArray)
{
libFunc(p_my2DArray.data(), M, N);
}
This way I could be able to call it without needed to give it again and again the size of the array (it's so easy to mix M and N):
void foo()
{
Double2DArray<42, 13> my2DArray ;
// etc.
libFunc(my2DArray);
}
This is how I would use multidimensional arrays and feed it to a C-like API expected a contiguous array of doubles.
P.S.: If M and N are not know at compile time, you only need to remove the template, and make the M and N parameters of the constructor, and everything works (almost) the same.
C++ uses row-major ordering so your multidimensional array is in fact a continuous 1-dimensional region in memory.
Even if declared for example 2-dimensional, it's accessed via index = x + y * height, so there should be no portability concerns...
The C++ documentation tells:
Multidimensional arrays are just an abstraction for programmers, since
we can obtain the same results with a simple array just by putting a
factor between its indices
(Here's also an explaination for visual c++)

Multi-Dimensional Arrays--> Null Object Pointers

I am trying to develop a C++ application. Part of the Application is meant to create and initiate some properties of an Object and then store the object in a multi-dimensional array. Problem is after Object creation and storing the objects in the array, retrieving the Object values gives me pointers to NULL.
Please see code below for exact implementation:
Cell** TestMain::convertToMatrix(){
//char[] lengthArr = arra[0];
//int[][] temp
int rowCount = getCurrentRowCount(); // Gives the row count of the multi-dimensional array
int colCount = getCurrentColCount(); // Gives the column count of the multi-dimensional array
Cell** cellList;
cellList = new Cell*[rowCount];
for (int rowIter=rowCount-1;rowIter>=0; rowIter-- ){
cellList[rowIter] = new Cell[colCount];
for (int colIter=colCount-1;colIter>=0;colIter--) {
Cell *currentCell = new Cell(arra[rowIter][colIter],rowIter,colIter);
//Calculate weights
if (0==currentCell->getValue()) currentCell->setWeight(0);
if (1== currentCell->getValue()) {
if (isEdge(rowIter,colIter)) {
currentCell->setWeight(1);
}
else {
//currentCell->setWeight(1 + getMinimumValue(cellList[rowIter+1][colIter]->getWeight(),cellList[rowIter+1][colIter+1]->getWeight(),cellList[rowIter][colIter+1]->getWeight() ) );
currentCell->setWeight(1 + getMinimumValue(cellList[rowIter+1][colIter].getWeight(),cellList[rowIter+1][colIter+1].getWeight(),cellList[rowIter][colIter+1].getWeight() ) );
}
}
cellList[rowIter][colIter] = *currentCell;
}
}
return cellList;
}
`
Here is the code that performs the checking later in the code:
void StrawberryMain::printField(Cell** arrayOfCells) {
int row=0;
int column=0;
int maxRowCount= getCurrentRowCount();
int maxColCount = getCurrentColCount();
for (;row<maxRowCount;row++) {
Cell *cellArr = arrayOfCells[row];
for (;column<maxColCount;column++) {
Cell currentArrayCell = cellArr[column];
/*if (currentArrayCell==NULL){ // This line throws an error ->No match for ‘operator==’ in ‘currentArrayCell == 0’. Why?
printf("Returned Pointer for Cell was NULL");
}
else { */
printf("%s(%s)|", currentArrayCell.getWeight(),currentArrayCell.getValue());
/
//}
printf("\n");
}
}
When I run the program I get a whole load of nulls printed on my screen as output.( One null for every object supposed stored in the array
I come from a Java background ( although I have dabbled in QT C++ before) so I am a bit miffed why this is happening. As much as I would appreciate an answer I would value an explanation as to why this happens ( or a link which explains why this happens) as I really want to understand the workings of the Language.
Thanks in anticipation.
There are several issues in your code.
As already stated in comments, you have a memory leak issue.
if (currentArrayCell==NULL){ // This line throws an error ->No match for ‘operator==’ in ‘currentArrayCell == 0’. Why?
currentArrayCell as declared in your code is a Cell object. Not a pointer to one. So you aren't comparing if a pointed to Cell is NULL. That line is trying to compare if a Cell == 0. And since you apparently haven't defined an equality operator that could work with a Cell and 0 the compiler raises that error.
With that in mind, you should note that the line Cell currentArrayCell = cellArr[column];
is actually creating a copy of a Cell. It may not be important this time. But if you write similar code where you would modify currentArrayCell, then you would find that any changes are only made to the local copy and not to the element in cellArr.
This line:
printf("%s(%s)|", currentArrayCell.getWeight(),currentArrayCell.getValue());
is most likely not doing what you wanted. s% means you must pass a string (meaning something like a const char*). However, based on your other code I'm guessing that those member functions are returning integers. printf is a low level tool and does not have the ability to convert between data types in that manner. You either need to use the appropriate format specifier for the data type (such as %d for int) or convert the values before passing them to printf.
So what happens when you use the wrong format specifier is that printf tries to byte-wise interpret whatever you actually passed as whatever type the format specifier implies. In your case, it's trying to interpret integers as character pointers. I'm actually surprised this isn't causing a crash instead of just printing nulls.
just to give you an idea
template<typename T>
struct array {
array(int m, int n) {
size_[0] = m, size_[1] = n;
data_.resize(m*n);
}
T* operator[](int i) {
return &data_.front() + i*size_[1];
}
private:
stdvector<T> data_;
size_t size_[2];
};
It seems clear from your code that you're a C guy doing C++, so here are some classes that should be aware of in light of your goals.
Boost's ublas has a matrix implementation that would be a generally superior alternative to creating your own implementation.
Baring that, at bare minimum you should probably be working with vectors instead of dynamically created arrays to reduce the potential for memory leaks.

Difference dynamic static 2d array c++

Im using opensource library called wxFreeChart to draw some XY charts. In example there is code which uses static array as a serie :
double data1[][2] = {
{ 10, 20, },
{ 13, 16, },
{ 7, 30, },
{ 15, 34, },
{ 25, 4, },
};
dataset->AddSerie((double *) data1, WXSIZEOF(dynamicArray));
WXSIZEOF ismacro defined like: sizeof(array)/sizeof(array[0])
In this case everything works great but in my program Im using dynamic arrays (according to users input).
I made a test and wrotecode like below:
double **dynamicArray = NULL;
dynamicArray = new double *[5] ;
for( int i = 0 ; i < 5 ; i++ )
dynamicArray[i] = new double[2];
dynamicArray [0][0] = 10;
dynamicArray [0][1] = 20;
dynamicArray [1][0] = 13;
dynamicArray [1][1] = 16;
dynamicArray [2][0] = 7;
dynamicArray [2][1] = 30;
dynamicArray [3][0] = 15;
dynamicArray [3][1] = 34;
dynamicArray [4][0] = 25;
dynamicArray [4][1] = 4;
dataset->AddSerie((double *) *dynamicArray, WXSIZEOF(dynamicArray));
But it doesnt work correctly. I mean point arent drawn. I wonder if there is any possibility that I can "cheat" that method and give it dynamic array in way it understands it and will read data from correct place
thanks for help
You can't use the WXSIZEOF macro on dynamically allocated arrays. That's for determining the size of an array, you have a pointer to an array :) You can't use that trick with non-compile-time constant arrays.
The parameter wants the number of pairs in the array - and uses a tricky macro to figure it out (using the macro is better for maintainability - there's only one place that uses the size constant).
You can probably simply pass 5 to the function (or whatever variable you use to determine the size of your array).
(I should add that I'm not familiar with this particular API... and it could be doing something funky that would make this not work... but I doubt it)
EDIT. It appears (from some comments) that this function does require contiguous storage.
I don't think you need to write your own function to put these elements contiguous in memory. That would be a lot of reallocation and copying. More likely, you should be using a different class. After browsing their very minimal documentation, it looks like you can use XYDynamicSerie to build a dynamic list of points, then adding it to an XYDynamicDataset or something.
If You define an array like
double myArr[5][2];
All cells occupy a continuous chunk of memory and I'm pretty sure dataset->AddSerie relies on that.
You can't guarantee that if you allocate memory in chunks, using consecutive calls to new.
My proposition is to write a simple class that allocates a continuous chunk of memory for storage and uses operator() to access that memory as a two dimensional array using 2 indices. Internally You can use a vector<double> to manage the storage, and You can pass the address of the first element of that vector to dataset->AddSerie
Please check the code in this C++ FAQ example and try to understand it. The matrix example uses new[] and delete[]. You should use a vector instead, and the type double instead of Fred
Where in the example, there is a private section like this
class Matrix {
public:
...
private:
unsigned nrows_, ncols_;
Fred* data_;
};
(The example shows a matrix of Freds) You should use a vector<double>
class Matrix {
public:
...
private:
unsigned nrows_, ncols_;
vector<double> data_;
};
That will make the code much simpler. You don't even need a destructor, because the vector manages the memory.
Using #Stephen's answer I created xy plot which can easyly process various data without messing with convertion to (double *) and SIZE<...> macro. Maybe this chunk of code will be interesting for someone.
...
// create plot
XYPlot *plot = new XYPlot();
// create dynamic dataset and serie
XYDynamicDataset *ddataset = new XYDynamicDataset();
XYDynamicSerie *dds = new XYDynamicSerie();
///add values. you can simply grab this data from other sources
/// such as std::vector filled by user
dds->AddXY(1.1, 1.1);
dds->AddXY(3.1, 2.1);
dds->AddXY(5.1, 1.8);
ddataset->AddSerie(dds);
ddataset->SetRenderer(new XYLineRenderer());
plot->AddDataset(ddataset);
...