boost:python passing an pointer to pointer as parameter - c++

First, i'm not a python programmer, so excuse my silly mistakes.
In C++ I have this public method from MyClass that creates a image dynamically and returns its size.
int MyClass::getImg(uchar *uimg[])
{
int size = variable_size;
*_uimg = new uchar[size];
memcpy(*_uimg, imageOrigin->data(), size);
uimg = _uimg;
return size;
}
And the boost:python:
BOOST_PYTHON_MODULE(mymodule)
{
class_<MyClass>("MyClass")
.def("getImg", &MyClass::getImg)
;
}
and when i try to use it in python:
def getImg():
img = c_char_p()
size = mymodule.MyClass.getImg(byref(img))
I'm getting this error:
Boost.Python.ArgumentError: Python argument types in
MyClass.getImg(MyClass, CArgObject, CArgObject)
did not match C++ signature:
getImg(class MyClass {lvalue}, unsigned char * *)
In python I also tried declaring
img = POINTER(c_ubyte)()
but that did'nt help either.
I googled it around for hours and i didn't came up with any good solution.
I just need access to that image in python, how can i get this done?

Revised and working version, exposing the data as a python list.
I am not sure how to implement this, but there may be a better way of implementing it, if you can choose your python interface freely. I think creating a list may be a better way to expose it. What do you expect from the return value? Maybe you can also wrap it a s a numpy array for better performance (there are also some questions on stackoverflow if you search for boost python and numphy)
class TestPtr
{
public:
int getImg(uchar **uimg)
{
int size = 9045;
uchar *_uimg = new uchar[size];
for( int i = 0; i < size; ++i )
_uimg[i] = i;
*uimg = _uimg;
return size;
}
};
boost::python::list getImgList( TestPtr &p )
{
uchar *uimg;
int rv = p.getImg(&uimg);
boost::python::list l;
for ( int i = 0; i < rv; ++i)
l.append( uimg[i] );
return l;
}
BOOST_PYTHON_MODULE(mymodule)
{
class_<TestPtr>("TestPtr")
.def("getImg",&getImgList)
;
}
Another hint, in your question, you have used the following line to call the method:
mymodule.MyClass.getImg()
This will make a class call (more or less equivalent to a static call) to your object. This is a mor ecorrect way to do it:
img = mymodule.MyClass()
data = img.getImg()

Related

Creating ArrayBuilders in a Loop

Is there any way to create a dynamic container of arrow::ArrayBuilder objects? Here is an example
int main(int argc, char** argv) {
std::size_t rowCount = 5;
arrow::MemoryPool* pool = arrow::default_memory_pool();
std::vector<arrow::Int64Builder> builders;
for (std::size_t i = 0; i < 2; i++) {
arrow::Int64Builder tmp(pool);
tmp.Reserve(rowCount);
builders.push_back(tmp);
}
return 0;
}
This yields error: variable ‘arrow::Int64Builder tmp’ has initializer but incomplete type
I am ideally trying to build a collection that will hold various builders and construct a table from row-wise data I am receiving. My guess is that this isn't the intended use for builders, but I couldn't find anything definitive in the Arrow documentation
What do your includes look like? That error message seems to suggest you are not including the right files. The full definition for arrow:Int64Builder is in arrow/array/builder_primitive.h but you can usually just include arrow/api.h to get everything.
The following compiles for me:
#include <iostream>
#include <arrow/api.h>
arrow::Status Main() {
std::size_t rowCount = 5;
arrow::MemoryPool* pool = arrow::default_memory_pool();
std::vector<arrow::Int64Builder> builders;
for (std::size_t i = 0; i < 2; i++) {
arrow::Int64Builder tmp(pool);
ARROW_RETURN_NOT_OK(tmp.Reserve(rowCount));
builders.push_back(std::move(tmp));
}
return arrow::Status::OK();
}
int main() {
auto status = Main();
if (!status.ok()) {
std::cerr << "Err: " << status << std::endl;
return 1;
}
return 0;
}
One small change to your example is that builders don't have a copy constructor / can't be copied. So I had to std::move it into the vector.
Also, if you want a single collection with many different types of builders then you probably want std::vector<std::unique_ptr<arrow::ArrayBuilder>> and you'll need to construct your builders on the heap.
One challenge you may run into is the fact that the builders all have different signatures for the Append method (e.g. the Int64Builder has Append(long) but the StringBuilder has Append(arrow::util::string_view)). As a result arrow::ArrayBuilder doesn't really have any Append methods (there are a few which take scalars, if you happen to already have your data as an Arrow C++ scalar). However, you can probably overcome this by casting to the appropriate type when you need to append.
Update:
If you really want to avoid casting and you know the schema ahead of time you could maybe do something along the lines of...
std::vector<std::function<arrow::Status(const Row&)>> append_funcs;
std::vector<std::shared_ptr<arrow::ArrayBuilder>> builders;
for (std::size_t i = 0; i < schema.fields().size(); i++) {
const auto& field = schema.fields()[i];
if (isInt32(field)) {
auto int_builder = std::make_shared<Int32Builder>();
append_funcs.push_back([int_builder] (const Row& row) ({
int val = row.GetCell<int>(i);
return int_builder->Append(val);
});
builders.push_back(std::move(int_builder));
} else if {
// Other types go here
}
}
// Later
for (const auto& row : rows) {
for (const auto& append_func : append_funcs) {
ARROW_RETURN_NOT_OK(append_func(row));
}
}
Note: I made up Row because I have no idea what format your data is in originally. Also I made up isInt32 because I don't recall how to check that off the top of my head.
This uses shared_ptr instead of unique_ptr because you need two copies, one in the capture of the lambda and the other in the builders array.

Unrestricted conversion from Array to TypedArray<std::complex<double>>?

Tried many things, just cannot get it to work when writing a mex-function.
I have an input from MATLAB which I pass to a method as const matlab::data::Array. This array may contain complex data, sometimes it's only real. So the most straightforward approach should be, in my naive thoughts, that I can simply convert the Array to a TypedArray<std::complex<double>> and I get full complex values if the array contains complex values, and I get complex values with imag=0 if the array contains only real values. It seems to be impossible... This last conversion is not accepted in any case, and MATLAB even simply crashes on trying to cast single elements from a real-valued Array to std::complex<double>.
Anybody a solution how to get a TypedArray<std::complex<double>> in all cases so I can use that in C++ code?
Story of my life, trying for hours and after posting here I find something that works within half an hour... Following code seems to do the job:
void prepareObject(const matlab::data::Array& corners, const matlab::data::Array& facets)
{
size_t N_facet_rows = facets.getDimensions()[0];
size_t N_facet_columns = facets.getDimensions()[1];
matlab::data::TypedArray<std::complex<double>> complex_facets = arrayFactory.createArray<std::complex<double>>(facets.getDimensions());
// Convert the facets to a complex-valued array.
if (facets.getType() == ArrayType::DOUBLE) {
std::complex<double> v;
// Input is DOUBLE, so for each value init a complex<double> and store that in the complex array.
v.imag(0);
for (int i_r = 0; i_r < N_facet_rows; i_r++) {
for (int i_c = 0; i_c < N_facet_columns; i_c++) {
v.real(facets[i_r][i_c]);
complex_facets[i_r][i_c] = v;
}
}
}
else {
// Input is COMPLEX_DOUBLE, so simply copy all values.
for (int i_r = 0; i_r < N_facet_rows; i_r++) {
for (int i_c = 0; i_c < N_facet_columns; i_c++) {
complex_facets[i_r][i_c] = (std::complex<double>) facets[i_r][i_c];
}
}
}

C++ pass a pointer to an array of unknown size and the function sizes and fills it

I'm sure there are a number of ways to solve this but I can't seem to find one. This is to get an idea of what I'd like to do:
void FillArray(_bstr_t *ptrArray)
{
ptrArray = new _bstr_t[100];
ptrArray[0] = "dfasef";
.
.
.
}
int main()
{
_bstr_t *ptrArray;
FillArray(ptrArray)
printf("%s", ptrArray[4]);
}
Very simple, use a reference, note the extra &
void FillArray(_bstr_t *&ptrArray)
{
ptrArray = new _bstr_t[100];
ptrArray[0] = "dfasef";
}

How to initialize an array of pointers (or do I need to do so at all)?

It's for my college exam, so don't ask why I'm not using advanced stuff in C++.
This is a console app. The problem to solve is to write missing functions inside defined structures. It is simulation of entrance exam so there's this question struct that has its attributes as follows:
char* _txtOfQuestion;
char* _answers[10]; //max 10 answers
int _correct; //location of the correct answer
int _points; //no. of points
Now, I need to implement the function Create() of this struct, which is responsible for initialising all the structure attributes.
I thought the parameters should be:
Create(char* text, char* answers[], int posOfCorrect, int points){
_txtOfQuestion = new char[strlen(text)+1];
strcpy_s(_txtOfQuestion , strlen(text), text);
// now this _question[10] attribute seems to be the toughest here
// as it happens to be an array
// how to initialize it here or if init. is not necessary, then
// how to assign it to this parameter answers, to that it fits?
// code here....
_correct = posOfCorrect;
_points = points;
}
Why don't you try something like this:
for (int i = 0; i < 10; ++i)
{
if (answers[i] != nullptr)
{
_answers[i] = malloc(strlen(answers[i])+1);
strcpy(_answers[i], answers[i]);
}
else
break;
}
of course you can omit nullptr check.
Is that helpful?

Trying to fill a 2d array of structures in C++

As above, I'm trying to create and then fill an array of structures with some starting data to then write to/read from.
I'm still writing the cache simulator as per my previous question:
Any way to get rid of the null character at the end of an istream get?
Here's how I'm making the array:
struct cacheline
{
string data;
string tag;
bool valid;
bool dirty;
};
cacheline **AllocateDynamicArray( int nRows, int nCols)
{
cacheline **dynamicArray;
dynamicArray = new cacheline*[nRows];
for( int i = 0 ; i < nRows ; i++ )
dynamicArray[i] = new cacheline [nCols];
return dynamicArray;
}
I'm calling this from main:
cacheline **cache = AllocateDynamicArray(nooflines,noofways);
It seems to create the array ok, but when I try to fill it I get memory errors, here's how I'm trying to do it:
int fillcache(cacheline **cache, int cachesize, int cachelinelength, int ways)
{
for (int j = 0; j < ways; j++)
{
for (int i = 0; i < cachesize/(cachelinelength*4); i++)
{
cache[i][ways].data = "EMPTY";
cache[i][ways].tag = "";
cache[i][ways].valid = 0;
cache[i][ways].dirty = 0;
}
}
return(1);
}
Calling it with:
fillcache(cache, cachesize, cachelinelength, noofways);
Now, this is the first time I've really tried to use dynamic arrays, so it's entirely possible I'm doing that completely wrong, let alone when trying to make it 2d, any ideas would be greatly appreciated :)
Also, is there an easier way to do write to/read from the array? At the moment (I think) I'm having to pass lots of variables to and from functions, including the array (or a pointer to the array?) each time which doesn't seem efficient?
Something else I'm unsure of, when I pass the array (pointer?) and edit the array, when I go back out of the function, will the array still be edited?
Thanks
Edit:
Just noticed a monumentally stupid error, it should ofcourse be:
cache[i][j].data = "EMPTY";
You should find your happiness. You just need the time to check it out (:
The way to happiness