Skip to content

Instantly share code, notes, and snippets.

@maleadt
Last active August 12, 2021 12:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maleadt/e47d7d88ebdd5f938ba8aebd3662646f to your computer and use it in GitHub Desktop.
Save maleadt/e47d7d88ebdd5f938ba8aebd3662646f to your computer and use it in GitHub Desktop.
CxxWrap pointer MWE
build
Manifest.toml
julia --project -e 'using Pkg; Pkg.instantiate()'
julia --project configure.jl
make -C build
julia --project wrap.jl
cmake_minimum_required(VERSION 3.13)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(wrap)
find_package(JlCxx)
add_library(wrap SHARED wrap.cpp)
target_link_libraries(wrap
JlCxx::cxxwrap_julia
)
install(TARGETS wrap
LIBRARY DESTINATION lib)
using CxxWrap
prefix = String[]
push!(prefix, dirname(Base.julia_cmd()[1]))
push!(prefix, CxxWrap.prefix_path())
run(`cmake -S $(@__DIR__) -B $(joinpath(@__DIR__, "build")) -DCMAKE_PREFIX_PATH=$(join(prefix, ';'))`)
[deps]
CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4"
#include <jlcxx/jlcxx.hpp>
#include <iostream>
template <typename T> struct MyCxxPtr {
typedef T value_type;
MyCxxPtr(T *ptr) : m_ptr(ptr) {}
// implicit conversion to a regular pointer
operator T *() const { return m_ptr; }
T *m_ptr;
};
void printit(float* a) {
std::cout << a << std::endl;
}
void foobar(MyCxxPtr<float> a) { printit(a); }
JLCXX_MODULE define_module(jlcxx::Module &mod) {
using namespace jlcxx;
// TODO: map_type directly to MyPtr?
mod.add_type<Parametric<TypeVar<1>>>("MyCxxPtr")
.apply<MyCxxPtr<float>>([](auto wrapped) {
typedef typename decltype(wrapped)::type WrappedT;
wrapped.template constructor<typename WrappedT::value_type*>();
});
mod.method("foobar", foobar);
}
using CxxWrap
# what I have: a custom primitive pointer type, and an array using it
primitive type MyPtr{T} 64 end
Base.cconvert(::Type{<:MyPtr}, x) = x
struct MyArray{T}
ptr::MyPtr{T}
end
Base.unsafe_convert(::Type{MyPtr{T}}, a::MyArray{T}) where {T} = a.ptr
# what I want: to pass a MyArray directly to a ccall with MyPtr, because that
# performs the necessary conversions automatically (keeping the array alive)
x = MyArray{Float32}(reinterpret(MyPtr{Float32}, Int(0xdeadbeef)))
# what ccall does:
@assert Base.unsafe_convert(MyPtr{Float32}, Base.cconvert(MyPtr{Float32}, x)) == x.ptr
# XXX: currently it seems impossible to `map_type` the parametric MyPtr directly,
# so we'll be using a MyCxxPtr as defined by CxxWrap's add_type and forward calls.
# this assumes that the layout of MyPtr is the same as the layout of MyCxxPtr.
# @wrapmodule(joinpath(@__DIR__, "build/libwrap.so"), :define_module)
@readmodule(joinpath(@__DIR__, "build/libwrap.so"), :define_module)
@wraptypes
# XXX: need to use <: MyCxxPtr because the actual values are MyCxxPtrAllocated <: MyCxxPtr
CxxWrap.argument_overloads(t::Type{<:MyCxxPtr{T}}) where {T} = [MyArray{T}]
@wrapfunctions
# forward calls
Base.cconvert(::Type{<:MyCxxPtr}, x) = x
Base.unsafe_convert(::Type{<:MyCxxPtr{T}}, ::MyArray{T}) where {T} =
MyCxxPtr{T}(reinterpret(Ptr{T}, Base.unsafe_convert(MyPtr{T}, x)))
## demo
# passing the C++-version of a pointer works as expected
foobar(MyCxxPtr{Float32}(C_NULL))
# passing an array doesn't, despite the `argument_overloads` above
# using InteractiveUtils
# @code_warntype foobar(x)
foobar(x)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment