-
-
Notifications
You must be signed in to change notification settings - Fork 51
/
Copy pathjniarray.jl
86 lines (78 loc) · 3.05 KB
/
jniarray.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
jniname(::Type{jboolean}) = "Boolean"
jniname(::Type{jbyte}) = "Byte"
jniname(::Type{jchar}) = "Char"
jniname(::Type{jshort}) = "Short"
jniname(::Type{jint}) = "Int"
jniname(::Type{jlong}) = "Long"
jniname(::Type{jfloat}) = "Float"
jniname(::Type{jdouble}) = "Double"
mutable struct JNIVector{T} <: AbstractVector{T}
ref::JavaRef
arr::Union{Nothing,Vector{T}}
function JNIVector{T}(ref) where T
j = new{T}(ref, nothing)
finalizer(deleteref, j)
return j
end
end
Base.getindex(jarr::JNIVector, args...) = getindex(jarr.arr, args...)
Base.setindex!(jarr::JNIVector, args...) = setindex!(jarr.arr, args...)
Base.size(jarr::JNIVector, args...; kwargs...) = size(jarr.arr, args...; kwargs...)
function deleteref(x::JNIVector{T}) where T
if x.arr !== nothing
release_elements(x)
end
deleteref(x.ref)
x.ref = J_NULL
end
signature(::Type{JNIVector{T}}) where T = string("[", signature(T))
jvalue(jarr::JNIVector) = jarr.ref.ptr
JNIVector{T}(ptr::Ptr{Nothing}) where {T} = JNIVector{T}(JavaLocalRef(ptr))
function convert(::Type{JNIVector{T}}, vec::Vector{T}) where {T}
arr = JNIVector{T}(length(vec))
arr .= vec
return arr
end
JNIVector(vec::Vector{T}) where {T} = convert(JNIVector{T}, vec)
for primitive in [:jboolean, :jchar, :jbyte, :jshort, :jint, :jlong, :jfloat, :jdouble]
name = jniname(eval(primitive))
get_elements = :(JNI.$(Symbol("Get$(name)ArrayElements")))
release_elements = :(JNI.$(Symbol("Release$(name)ArrayElements")))
new_array = :(JNI.$(Symbol("New$(name)Array")))
m = quote
function get_elements!(jarr::JNIVector{$primitive})
sz = Int(JNI.GetArrayLength(jarr.ref.ptr))
# Free the array in release_elements rather than directly via GC
jarr.arr = unsafe_wrap(Array, $get_elements(jarr.ref.ptr, Ptr{jboolean}(C_NULL)), sz; own = false)
jarr
end
JNIVector{$primitive}(sz::Int) = get_elements!(JNIVector{$primitive}($new_array(sz)))
function release_elements(arg::JNIVector{$primitive})
# Make sure that JVM has not been destroyed
if JNI.ppenv[1] != C_NULL
arr = arg.arr
ref = arg.ref
# The correct way would be let ccall handle this by removing typing from JNI wrappers
GC.@preserve arg ref arr begin
$release_elements(ref.ptr, pointer(arr), jint(0))
end
end
arg.arr = nothing
end
function convert_result(::Type{JNIVector{$primitive}}, ptr)
get_elements!(JNIVector{$primitive}(ptr))
end
function convert_arg(argtype::Type{Vector{$primitive}}, arg::JNIVector{$primitive})
release_elements(arg)
return arg, arg
end
function convert_arg(argtype::Type{JNIVector{$primitive}}, arg::JNIVector{$primitive})
release_elements(arg)
return arg, arg
end
function cleanup_arg(jarr::JNIVector{$primitive})
get_elements!(jarr)
end
end
eval(m)
end