Passing an array of a C++ class to julia (CxxWrap)

question

#1

Hi,

I’ve been wrapping a C++ library with C++ wrap, and some of the methods in it return vectors, either of simple items like floats, and ints, or sometimes vectors of classes.

I’ve come up with a way to give a std::vector to julia by doing the following:

.method("get_fw_nodes", [](SequenceGraph& sg, sgNodeID_t n) {
                std::vector<sgNodeID_t> fw_nodes = sg.get_fw_nodes(n);
                auto *nodes = new sgNodeID_t[fw_nodes.size()];
                std::copy(fw_nodes.begin(), fw_nodes.end(), nodes);
                auto jlarr = jlcxx::make_julia_array(nodes, fw_nodes.size());
                return jlarr;
            })

So I call the method, get the vector, allocate a new array, copy vector contents to the array, wrap that up in an ArrayRef and pass that to julia. This works great for this case as sgNodeID_t is just int64_t.
The use of a new without a paired delete scares me, but I’m trusting julia gc to take care of that, as I believe jccxx::make_julia_array ensures the resulting Array is owned by julia and so should be gc’d.

I’d like to do something similar, passing an array of a C++ class. The class is wrapped in CxxWrap too:

mod.add_type<Link>("Link")
            .constructor()
            .constructor<sgNodeID_t, sgNodeID_t, int32_t>();

However trying to do something like this:

.method("get_fw_links", [](SequenceGraph& sg, sgNodeID_t n){
                std::vector<Link> fw_links = sg.get_fw_links(n);
                auto *links = new Link[fw_links.size()];
                std::copy(fw_links.begin(), fw_links.end(), links);
                auto jlarr = jlcxx::make_julia_array(links, fw_links.size());
                return jlarr;
            })

Doesn’t work. Is it at all possible using CxxWrap and any other julia c/c++ interfacing to pass to julia an array of C++ objects (which are themselves CxxWrapped)? I know an alternative route is to wrap std::vector.


#2

Or just allocate the vector on the julia side and pass it to get_fw_links to be initialized (since You already the size?)


#3

std::vector stores classes contiguously, whereas julia array’s don’t nessecerily do that. Presumably even if I allocated on the Julia side, say Vector{LinkRef} or Vector{LinkAllocated}, I would need some way on the C++ side, to box up each Link object so as it can be given to those julia arrays and not eliminated by C++ destructors?


#4

I’m not sure I understand why you want to copy the data in the first place.
Please take a look here: https://github.com/jstrube/LCIOWrapBuilder/blob/master/src/MCParticle.icc#L20
This wraps a method that returns a vector of objects. MCParticleVec is just a typedef to an std::vector<MCParticle>. The C++ API is here: http://lcio.desy.de/v02-09/doc/doxygen_api/html/classEVENT_1_1MCParticle.html
Then I just wrap at and size of the std::vector and make an iterator on the Julia side.
Does that help?


#5

This approach (wrapping at and length as getindex and length and writing an iterator in Julia) worked out for me as well, but I would prefer a solution which could handle all std::vector's in one go - preferably built-in to CxxWrap, similar to functionality in Cxx.

But in any case - I am very grateful for CxxWrap and the solution posted here.