-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
refpointer.jl
114 lines (94 loc) · 4.47 KB
/
refpointer.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# This file is a part of Julia. License is MIT: https://julialang.org/license
"""
Ref{T}
An object that safely references data of type `T`. This type is guaranteed to point to
valid, Julia-allocated memory of the correct type. The underlying data is protected from
freeing by the garbage collector as long as the `Ref` itself is referenced.
In Julia, `Ref` objects are dereferenced (loaded or stored) with `[]`.
Creation of a `Ref` to a value `x` of type `T` is usually written `Ref(x)`.
Additionally, for creating interior pointers to containers (such as Array or Ptr),
it can be written `Ref(a, i)` for creating a reference to the `i`-th element of `a`.
When passed as a `ccall` argument (either as a `Ptr` or `Ref` type), a `Ref` object will be
converted to a native pointer to the data it references.
There is no invalid (NULL) `Ref` in Julia, but a `C_NULL` instance of `Ptr` can be passed to a `ccall` Ref argument.
"""
Ref
# C NUL-terminated string pointers; these can be used in ccall
# instead of Ptr{Cchar} and Ptr{Cwchar_t}, respectively, to enforce
# a check for embedded NUL chars in the string (to avoid silent truncation).
if Int === Int64
primitive type Cstring 64 end
primitive type Cwstring 64 end
else
primitive type Cstring 32 end
primitive type Cwstring 32 end
end
### General Methods for Ref{T} type
eltype(x::Type{<:Ref{T}}) where {T} = @isdefined(T) ? T : Any
convert(::Type{Ref{T}}, x::Ref{T}) where {T} = x
# create Ref objects for general object conversion
unsafe_convert(::Type{Ref{T}}, x::Ref{T}) where {T} = unsafe_convert(Ptr{T}, x)
unsafe_convert(::Type{Ref{T}}, x) where {T} = unsafe_convert(Ptr{T}, x)
convert(::Type{Ref{T}}, x) where {T} = RefValue{T}(x)
### Methods for a Ref object that is backed by an array at index i
struct RefArray{T,A<:AbstractArray{T},R} <: Ref{T}
x::A
i::Int
roots::R # should be either ::Nothing or ::Any
RefArray{T,A,R}(x,i,roots=nothing) where {T,A<:AbstractArray{T},R} = new(x,i,roots)
end
RefArray(x::AbstractArray{T}, i::Int, roots::Any) where {T} = RefArray{T,typeof(x),Any}(x, i, roots)
RefArray(x::AbstractArray{T}, i::Int=1, roots::Nothing=nothing) where {T} = RefArray{T,typeof(x),Nothing}(x, i, nothing)
convert(::Type{Ref{T}}, x::AbstractArray{T}) where {T} = RefArray(x, 1)
function unsafe_convert(P::Type{Ptr{T}}, b::RefArray{T}) where T
if datatype_pointerfree(RefValue{T})
p = pointer(b.x, b.i)
elseif isconcretetype(T) && T.mutable
p = pointer_from_objref(b.x[b.i])
else
# see comment on equivalent branch for RefValue
p = pointerref(Ptr{Ptr{Cvoid}}(pointer(b.x, b.i)), 1, Core.sizeof(Ptr{Cvoid}))
end
return convert(P, p)
end
function unsafe_convert(P::Type{Ptr{Any}}, b::RefArray{Any})
return convert(P, pointer(b.x, b.i))
end
unsafe_convert(::Type{Ptr{Cvoid}}, b::RefArray{T}) where {T} = convert(Ptr{Cvoid}, unsafe_convert(Ptr{T}, b))
###
if is_primary_base_module
Ref(x::Any) = RefValue(x)
Ref{T}() where {T} = RefValue{T}() # Ref{T}()
Ref{T}(x) where {T} = RefValue{T}(x) # Ref{T}(x)
Ref(x::Ref, i::Integer) = (i != 1 && error("Ref only has one element"); x)
Ref(x::Ptr{T}, i::Integer) where {T} = x + (i - 1) * Core.sizeof(T)
# convert Arrays to pointer arrays for ccall
function Ref{P}(a::Array{<:Union{Ptr,Cwstring,Cstring}}) where P<:Union{Ptr,Cwstring,Cstring}
return RefArray(a) # effectively a no-op
end
function Ref{P}(a::Array{T}) where P<:Union{Ptr,Cwstring,Cstring} where T
if (!isbits(T) && T <: eltype(P))
# this Array already has the right memory layout for the requested Ref
return RefArray(a,1,false) # root something, so that this function is type-stable
else
ptrs = Vector{P}(undef, length(a)+1)
roots = Vector{Any}(undef, length(a))
for i = 1:length(a)
root = cconvert(P, a[i])
ptrs[i] = unsafe_convert(P, root)::P
roots[i] = root
end
ptrs[length(a)+1] = C_NULL
return RefArray(ptrs,1,roots)
end
end
Ref(x::AbstractArray, i::Integer) = RefArray(x, i)
end
cconvert(::Type{Ptr{P}}, a::Array{<:Ptr}) where {P<:Ptr} = a
cconvert(::Type{Ref{P}}, a::Array{<:Ptr}) where {P<:Ptr} = a
cconvert(::Type{Ptr{P}}, a::Array) where {P<:Union{Ptr,Cwstring,Cstring}} = Ref{P}(a)
cconvert(::Type{Ref{P}}, a::Array) where {P<:Union{Ptr,Cwstring,Cstring}} = Ref{P}(a)
###
getindex(b::RefArray) = b.x[b.i]
setindex!(b::RefArray, x) = (b.x[b.i] = x; b)
###