What is the best (or a good) way of solving the following very generic problem? I’d like to
- call
obj_alloc()
andobj_free()
in some C library from Julia. On the Julia side, work withPtr{obj}
. It can be considered opaque, it is only passed to other functions in the same library. - Have Julia GC handle calling
obj_free
for me, probably with a wrapper. - Have the simplest interface to the wrapped object possible. The user shouldn’t have to know where it comes from.
- When using the
obj
, have as small a performance degradation as possible compared to usingPtr{obj}
directly.
So, in particular, things like wrapping the alloc in a try
block and freeing in finally
, is not what I’m looking for.
For example, here is an attempt for random number generators in GSL (gnu scientific library)
using GSL: GSL
struct RNG
x::Ptr{GSL.gsl_rng}
_y::Ref
function RNG(rng_type=GSL.gsl_rng_taus2)
_rng = GSL.rng_alloc(rng_type)
mrng = Ref(_rng)
rng = new(_rng, mrng)
finalizer(x -> GSL.rng_free(rng.x), mrng)
return rng
end
end
(rng::RNG)() = rng.x
Comments
- This apparently uses more memory than just using
Ptr
. - In some tests generating uniform random samples, I see no performance degradation.
- If I use a
mutable struct
as a wrapper, instead ofstruct
, there is a loss of performance. - I use
Ref
above for convenience, but amutable struct
wrapper also works for the second field.
It seems like there must be a simpler way, but I don’t see it.
Here is a more generic version
struct AllocFree{T, AF, FF}
x::Ptr{T}
_y::Ref
function AllocFree{T,AF,FF}(args...) where {T, AF, FF}
_obj = AF.instance(args...)
mobj = Ref(_obj)
obj = new{T,AF,FF}(_obj, mobj)
finalizer(x -> FF.instance(obj.x), mobj)
return obj
end
end
(obj::AllocFree)() = obj.x
Then
julia> using GSL;
julia> mkrng(t=GSL.gsl_rng_taus2) = AllocFree{GSL.gsl_rng, typeof(GSL.rng_alloc), typeof(GSL.rng_free)}(t);
julia> rng = mkrng()
AllocFree{gsl_rng, typeof(rng_alloc), typeof(rng_free)}(Ptr{gsl_rng} @0x0000000002677af0, Base.RefValue{Ptr{gsl_rng}}(Ptr{gsl_rng} @0x0000000002677af0))
julia> GSL.ran_flat(rng(), 0.0, 1.0)
0.18691460322588682