Skip to content

Commit b7844ae

Browse files
committed
Allow arrays of tuples and tuples as function arguments
Fixes JuliaInterop/CxxWrap.jl#478
1 parent 28aa59c commit b7844ae

File tree

3 files changed

+101
-0
lines changed

3 files changed

+101
-0
lines changed

examples/containers.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,45 @@ const double* const_matrix()
1818
return &d[0][0];
1919
}
2020

21+
// Tuple array test
22+
std::tuple<jlcxx::Array<double>, jlcxx::Array<double>>
23+
make_array_tuple()
24+
{
25+
jlcxx::Array<double> x;
26+
jlcxx::Array<double> y;
27+
28+
x.push_back(1.0);
29+
x.push_back(2.0);
30+
y.push_back(3.0);
31+
32+
return std::make_tuple(x, y);
33+
}
34+
35+
std::tuple<double,int,bool> copy_tuple(std::tuple<double,int,bool> t)
36+
{
37+
return t;
38+
}
39+
40+
std::vector<double> read_array_tuple(std::tuple<jlcxx::ArrayRef<double>, jlcxx::ArrayRef<double>> t)
41+
{
42+
jlcxx::ArrayRef<double> x = std::get<0>(t);
43+
jlcxx::ArrayRef<double> y = std::get<1>(t);
44+
45+
std::vector<double> result;
46+
47+
for(auto el : x)
48+
{
49+
result.push_back(el);
50+
}
51+
52+
for(auto el : y)
53+
{
54+
result.push_back(el);
55+
}
56+
57+
return result;
58+
}
59+
2160
JLCXX_MODULE define_julia_module(jlcxx::Module& containers)
2261
{
2362
using namespace jlcxx;
@@ -81,4 +120,7 @@ JLCXX_MODULE define_julia_module(jlcxx::Module& containers)
81120
return result;
82121
});
83122
containers.method("uint8_ptr", [] (uint8_t* x) { return int(*x); });
123+
containers.method("copy_tuple", &copy_tuple);
124+
containers.method("make_array_tuple", &make_array_tuple);
125+
containers.method("read_array_tuple", &read_array_tuple);
84126
}

include/jlcxx/array.hpp

+18
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,24 @@ struct ConvertToCpp<ArrayRef<T,Dim>, CxxWrappedTrait<SubTraitT>>
415415
}
416416
};
417417

418+
template<typename CppT>
419+
struct BoxValue<CppT,jl_array_t*>
420+
{
421+
inline jl_value_t* operator()(CppT arr)
422+
{
423+
return (jl_value_t*)arr.wrapped();
424+
}
425+
};
426+
427+
template<typename ElementT, int Dim>
428+
struct UnboxValue<ArrayRef<ElementT,Dim>, jl_array_t*>
429+
{
430+
inline ArrayRef<ElementT,Dim> operator()(jl_value_t* arr)
431+
{
432+
return ArrayRef<ElementT,Dim>(reinterpret_cast<jl_array_t*>(arr));
433+
}
434+
};
435+
418436
// Iterator operator implementation
419437
template<typename PointedT, typename CppT>
420438
bool operator!=(const array_iterator_base<PointedT, CppT>& l, const array_iterator_base<PointedT, CppT>& r)

include/jlcxx/tuple.hpp

+41
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,32 @@ struct TraitSelector<std::tuple<TypesT...>>
6767
using type = TupleTrait;
6868
};
6969

70+
// Tuples are always copied because the memory layout in C++ and Julia is different, so references and pointers are not allowed
71+
template<typename... TypesT>
72+
struct TraitSelector<std::tuple<TypesT...>&>
73+
{
74+
using type = TupleTrait;
75+
static_assert(sizeof(std::tuple<TypesT...>) == 0, "References to Julia tuples can't be used. Pass the tuple by value instead.");
76+
};
77+
template<typename... TypesT>
78+
struct TraitSelector<const std::tuple<TypesT...>&>
79+
{
80+
using type = TupleTrait;
81+
static_assert(sizeof(std::tuple<TypesT...>) == 0, "References to Julia tuples can't be used. Pass the tuple by value instead.");
82+
};
83+
template<typename... TypesT>
84+
struct TraitSelector<std::tuple<TypesT...>*>
85+
{
86+
using type = TupleTrait;
87+
static_assert(sizeof(std::tuple<TypesT...>) == 0, "Pointers to Julia tuples can't be used. Pass the tuple by value instead.");
88+
};
89+
template<typename... TypesT>
90+
struct TraitSelector<const std::tuple<TypesT...>*>
91+
{
92+
using type = TupleTrait;
93+
static_assert(sizeof(std::tuple<TypesT...>) == 0, "Pointers to Julia tuples can't be used. Pass the tuple by value instead.");
94+
};
95+
7096
template<typename... TypesT>
7197
struct MappingTrait<std::tuple<TypesT...>, TupleTrait>
7298
{
@@ -106,6 +132,21 @@ struct ConvertToJulia<std::tuple<TypesT...>, TupleTrait>
106132
}
107133
};
108134

135+
template<typename... TypesT>
136+
struct ConvertToCpp<std::tuple<TypesT...>, TupleTrait>
137+
{
138+
using cpp_t = std::tuple<TypesT...>;
139+
inline cpp_t operator()(jl_value_t* julia_val) const
140+
{
141+
constexpr std::size_t tup_sz = std::tuple_size<cpp_t>::value;
142+
auto unpack_tuple = [&]<std::size_t... Is>(std::index_sequence<Is...>)
143+
{
144+
return std::make_tuple((unbox<std::tuple_element_t<Is, cpp_t>>(jl_get_nth_field_checked(julia_val, Is)))...);
145+
};
146+
return unpack_tuple(std::make_index_sequence<tup_sz>{});
147+
}
148+
};
149+
109150
// Wrap NTuple type
110151
template<typename N, typename T>
111152
struct NTuple

0 commit comments

Comments
 (0)