I’m creating a package which interfaces to a C library with C structs, and implements all the operator overloading for these structs. For example it looks a bit like
mutable struct MyStruct
t::Ptr{CStruct}
# Constructor/finalizer not shown for brevity
end
function f(x)
return log(1+x)*1/sin(exp(x))
end
t = MyStruct()
a = f(t)
Currently, the operators are overloaded so that a new MyStruct
is created for each operator output (e.g. for +(t1::MyStruct, t2::MyStruct)
, new memory is malloc-ed in C holding the return struct). I’ve implemented the finalizer for MyStruct
so that the memory is freed when the resulting variable goes out of scope. This works, however it is slow because the memory for each struct is not compact for every temporary evaluated in the expression. For example, with log(1+x)*1/sin(exp(x))
, the result 1+x
creates a new MyStruct
on the heap, then result log(1+x)
makes another new MyStruct
on the heap, etc). The C code includes a permanent array of preallocated structs I should be using for the temporaries in the expressions, to minimize cache misses in the evaluation of an expression. Preliminary testing with this shows a significant speedup.
The problem is that, I need to be able to distinguish between the temporaries stored in a preallocated buffer, and heap allocated memory which follows the Julia garbage collection/is stored in local variables. Currently there is a C++ interface of this C package, where the operators are overloaded so that they all return a separate temporary type. Then the assignment operator =
is overloaded in the C++ so that at the end of the expression evaluation, the temporary type is copied to a heap allocated struct.
Unfortunately though, unlike C++, Julia does not allow me to overload assignment. I could use a macro for the assignment to do this conversion at the end, however that looks messy and defeats the purpose of taking advantage of type-stable generic expressions in Julia