• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37662

25 Oct 2023 07:08AM UTC coverage: 87.999% (+1.5%) from 86.476%
#37662

push

local

web-flow
Improve efficiency of minimum/maximum(::Diagonal) (#30236)

```
julia> DM = Diagonal(rand(100));

julia> @btime minimum($DM);    # before
  27.987 μs (0 allocations: 0 bytes)

julia> @btime minimum($DM);    # after
  246.091 ns (0 allocations: 0 bytes)
```

8 of 8 new or added lines in 1 file covered. (100.0%)

74065 of 84166 relevant lines covered (88.0%)

12219725.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.72
/base/pointer.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
    Ptr{T}
5

6
A memory address referring to data of type `T`.  However, there is no guarantee that the
7
memory is actually valid, or that it actually represents data of the specified type.
8
"""
9
Ptr
10

11
## converting pointers to an appropriate unsigned ##
12

13
"""
14
    C_NULL
15

16
The C null pointer constant, sometimes used when calling external code.
17
"""
18
const C_NULL = bitcast(Ptr{Cvoid}, 0)
19

20
# TODO: deprecate these conversions. C doesn't even allow them.
21

22
# pointer to integer
23
convert(::Type{T}, x::Ptr) where {T<:Integer} = T(UInt(x))::T
200,921✔
24

25
# integer to pointer
26
convert(::Type{Ptr{T}}, x::Union{Int,UInt}) where {T} = Ptr{T}(x)
1,446,327,980✔
27

28
# pointer to pointer
29
convert(::Type{Ptr{T}}, p::Ptr{T}) where {T} = p
185✔
30
convert(::Type{Ptr{T}}, p::Ptr) where {T} = bitcast(Ptr{T}, p)::Ptr{T}
1,168,383,686✔
31

32
# object to pointer (when used with ccall)
33

34
"""
35
    unsafe_convert(T, x)
36

37
Convert `x` to a C argument of type `T`
38
where the input `x` must be the return value of `cconvert(T, ...)`.
39

40
In cases where [`convert`](@ref) would need to take a Julia object
41
and turn it into a `Ptr`, this function should be used to define and perform
42
that conversion.
43

44
Be careful to ensure that a Julia reference to `x` exists as long as the result of this
45
function will be used. Accordingly, the argument `x` to this function should never be an
46
expression, only a variable name or field reference. For example, `x=a.b.c` is acceptable,
47
but `x=[a,b,c]` is not.
48

49
The `unsafe` prefix on this function indicates that using the result of this function after
50
the `x` argument to this function is no longer accessible to the program may cause undefined
51
behavior, including program corruption or segfaults, at any later time.
52

53
See also [`cconvert`](@ref)
54
"""
55
function unsafe_convert end
56

57
# convert strings to String etc. to pass as pointers
58
cconvert(::Type{Ptr{UInt8}}, s::AbstractString) = String(s)
60✔
59
cconvert(::Type{Ptr{Int8}}, s::AbstractString) = String(s)
2✔
60
unsafe_convert(::Type{Ptr{UInt8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{UInt8}, (Any,), x)
5,531,089✔
61
unsafe_convert(::Type{Ptr{Int8}}, x::Symbol) = ccall(:jl_symbol_name, Ptr{Int8}, (Any,), x)
69,890,511✔
62
unsafe_convert(::Type{Ptr{UInt8}}, s::String) = ccall(:jl_string_ptr, Ptr{UInt8}, (Any,), s)
695,436,982✔
63
unsafe_convert(::Type{Ptr{Int8}}, s::String) = ccall(:jl_string_ptr, Ptr{Int8}, (Any,), s)
3,102,180✔
64

65
unsafe_convert(::Type{Ptr{T}}, a::Array{T}) where {T} = ccall(:jl_array_ptr, Ptr{T}, (Any,), a)
675,332,810✔
66
unsafe_convert(::Type{Ptr{S}}, a::AbstractArray{T}) where {S,T} = convert(Ptr{S}, unsafe_convert(Ptr{T}, a))
18,469,232✔
67
unsafe_convert(::Type{Ptr{T}}, a::AbstractArray{T}) where {T} = error("conversion to pointer not defined for $(typeof(a))")
9✔
68
# TODO: add this deprecation to give a better error:
69
# cconvert(::Type{<:Ptr}, a::AbstractArray) = error("conversion to pointer not defined for $(typeof(a))")
70
# unsafe_convert(::Type{Ptr{T}}, a::AbstractArray{T}) where {T} = error("missing call to cconvert for call to unsafe_convert for AbstractArray")
71

72
# unsafe pointer to array conversions
73
"""
74
    unsafe_wrap(Array, pointer::Ptr{T}, dims; own = false)
75

76
Wrap a Julia `Array` object around the data at the address given by `pointer`,
77
without making a copy.  The pointer element type `T` determines the array
78
element type. `dims` is either an integer (for a 1d array) or a tuple of the array dimensions.
79
`own` optionally specifies whether Julia should take ownership of the memory,
80
calling `free` on the pointer when the array is no longer referenced.
81

82
This function is labeled "unsafe" because it will crash if `pointer` is not
83
a valid memory address to data of the requested length. Unlike [`unsafe_load`](@ref)
84
and [`unsafe_store!`](@ref), the programmer is responsible also for ensuring that the
85
underlying data is not accessed through two arrays of different element type, similar
86
to the strict aliasing rule in C.
87
"""
88
function unsafe_wrap(::Union{Type{Array},Type{Array{T}},Type{Array{T,N}}},
8,820✔
89
                     p::Ptr{T}, dims::NTuple{N,Int}; own::Bool = false) where {T,N}
90
    ccall(:jl_ptr_to_array, Array{T,N}, (Any, Ptr{Cvoid}, Any, Int32),
4,410✔
91
          Array{T,N}, p, dims, own)
92
end
93
function unsafe_wrap(::Union{Type{Array},Type{Array{T}},Type{Array{T,1}}},
105,463✔
94
                     p::Ptr{T}, d::Integer; own::Bool = false) where {T}
95
    ccall(:jl_ptr_to_array_1d, Array{T,1},
53,050✔
96
          (Any, Ptr{Cvoid}, Csize_t, Cint), Array{T,1}, p, d, own)
97
end
98
unsafe_wrap(Atype::Union{Type{Array},Type{Array{T}},Type{Array{T,N}}},
×
99
            p::Ptr{T}, dims::NTuple{N,<:Integer}; own::Bool = false) where {T,N} =
8,290✔
100
    unsafe_wrap(Atype, p, convert(Tuple{Vararg{Int}}, dims), own = own)
101

102
"""
103
    unsafe_load(p::Ptr{T}, i::Integer=1)
104
    unsafe_load(p::Ptr{T}, order::Symbol)
105
    unsafe_load(p::Ptr{T}, i::Integer, order::Symbol)
106

107
Load a value of type `T` from the address of the `i`th element (1-indexed) starting at `p`.
108
This is equivalent to the C expression `p[i-1]`. Optionally, an atomic memory ordering can
109
be provided.
110

111
The `unsafe` prefix on this function indicates that no validation is performed on the
112
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
113
that referenced memory is not freed or garbage collected while invoking this function.
114
Incorrect usage may segfault your program or return garbage answers. Unlike C, dereferencing
115
memory region allocated as different type may be valid provided that the types are compatible.
116

117
!!! compat "Julia 1.10"
118
     The `order` argument is available as of Julia 1.10.
119

120
See also: [`atomic`](@ref)
121
"""
122
unsafe_load(p::Ptr, i::Integer=1) = pointerref(p, Int(i), 1)
2,147,483,647✔
123
unsafe_load(p::Ptr, order::Symbol) = atomic_pointerref(p, order)
55✔
124
function unsafe_load(p::Ptr, i::Integer, order::Symbol)
×
125
    unsafe_load(p + (elsize(typeof(p)) * (Int(i) - 1)), order)
×
126
end
127

128
"""
129
    unsafe_store!(p::Ptr{T}, x, i::Integer=1)
130
    unsafe_store!(p::Ptr{T}, x, order::Symbol)
131
    unsafe_store!(p::Ptr{T}, x, i::Integer, order::Symbol)
132

133
Store a value of type `T` to the address of the `i`th element (1-indexed) starting at `p`.
134
This is equivalent to the C expression `p[i-1] = x`. Optionally, an atomic memory ordering
135
can be provided.
136

137
The `unsafe` prefix on this function indicates that no validation is performed on the
138
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
139
that referenced memory is not freed or garbage collected while invoking this function.
140
Incorrect usage may segfault your program. Unlike C, storing memory region allocated as
141
different type may be valid provided that that the types are compatible.
142

143
!!! compat "Julia 1.10"
144
     The `order` argument is available as of Julia 1.10.
145

146
See also: [`atomic`](@ref)
147
"""
148
unsafe_store!(p::Ptr{Any}, @nospecialize(x), i::Integer=1) = pointerset(p, x, Int(i), 1)
1✔
149
unsafe_store!(p::Ptr{T}, x, i::Integer=1) where {T} = pointerset(p, convert(T,x), Int(i), 1)
228,309,135✔
150
unsafe_store!(p::Ptr{T}, x, order::Symbol) where {T} = atomic_pointerset(p, x isa T ? x : convert(T,x), order)
13✔
151
function unsafe_store!(p::Ptr, x, i::Integer, order::Symbol)
×
152
    unsafe_store!(p + (elsize(typeof(p)) * (Int(i) - 1)), x, order)
×
153
end
154

155
"""
156
    unsafe_modify!(p::Ptr{T}, op, x, [order::Symbol]) -> Pair
157

158
These atomically perform the operations to get and set a memory address after applying
159
the function `op`. If supported by the hardware (for example, atomic increment), this may be
160
optimized to the appropriate hardware instruction, otherwise its execution will be
161
similar to:
162

163
    y = unsafe_load(p)
164
    z = op(y, x)
165
    unsafe_store!(p, z)
166
    return y => z
167

168
The `unsafe` prefix on this function indicates that no validation is performed on the
169
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
170
that referenced memory is not freed or garbage collected while invoking this function.
171
Incorrect usage may segfault your program.
172

173
!!! compat "Julia 1.10"
174
     This function requires at least Julia 1.10.
175

176
See also: [`modifyproperty!`](@ref Base.modifyproperty!), [`atomic`](@ref)
177
"""
178
function unsafe_modify!(p::Ptr, op, x, order::Symbol=:not_atomic)
30✔
179
    return atomic_pointermodify(p, op, x, order)
30✔
180
end
181

182
"""
183
    unsafe_replace!(p::Ptr{T}, expected, desired,
184
                   [success_order::Symbol[, fail_order::Symbol=success_order]]) -> (; old, success::Bool)
185

186
These atomically perform the operations to get and conditionally set a memory address to
187
a given value. If supported by the hardware, this may be optimized to the appropriate
188
hardware instruction, otherwise its execution will be similar to:
189

190
    y = unsafe_load(p, fail_order)
191
    ok = y === expected
192
    if ok
193
        unsafe_store!(p, desired, success_order)
194
    end
195
    return (; old = y, success = ok)
196

197
The `unsafe` prefix on this function indicates that no validation is performed on the
198
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
199
that referenced memory is not freed or garbage collected while invoking this function.
200
Incorrect usage may segfault your program.
201

202
!!! compat "Julia 1.10"
203
     This function requires at least Julia 1.10.
204

205
See also: [`replaceproperty!`](@ref Base.replaceproperty!), [`atomic`](@ref)
206
"""
207
function unsafe_replace!(p::Ptr{T}, expected, desired, success_order::Symbol=:not_atomic, fail_order::Symbol=success_order) where {T}
28✔
208
    @inline
28✔
209
    xT = desired isa T ? desired : convert(T, desired)
28✔
210
    return atomic_pointerreplace(p, expected, xT, success_order, fail_order)
28✔
211
end
212
function unsafe_replace!(p::Ptr{Any}, @nospecialize(expected), @nospecialize(desired), success_order::Symbol=:not_atomic, fail_order::Symbol=success_order)
5✔
213
    return atomic_pointerreplace(p, expected, desired, success_order, fail_order)
5✔
214
end
215

216
"""
217
    unsafe_swap!(p::Ptr{T}, x, [order::Symbol])
218

219
These atomically perform the operations to simultaneously get and set a memory address.
220
If supported by the hardware, this may be optimized to the appropriate hardware
221
instruction, otherwise its execution will be similar to:
222

223
    y = unsafe_load(p)
224
    unsafe_store!(p, x)
225
    return y
226

227
The `unsafe` prefix on this function indicates that no validation is performed on the
228
pointer `p` to ensure that it is valid. Like C, the programmer is responsible for ensuring
229
that referenced memory is not freed or garbage collected while invoking this function.
230
Incorrect usage may segfault your program.
231

232
!!! compat "Julia 1.10"
233
     This function requires at least Julia 1.10.
234

235
See also: [`swapproperty!`](@ref Base.swapproperty!), [`atomic`](@ref)
236
"""
237
function unsafe_swap!(p::Ptr{Any}, x, order::Symbol=:not_atomic)
2✔
238
    return atomic_pointerswap(p, x, order)
2✔
239
end
240
function unsafe_swap!(p::Ptr{T}, x, order::Symbol=:not_atomic) where {T}
11✔
241
    @inline
11✔
242
    xT = x isa T ? x : convert(T, x)
11✔
243
    return atomic_pointerswap(p, xT, order)
11✔
244
end
245

246
# convert a raw Ptr to an object reference, and vice-versa
247
"""
248
    unsafe_pointer_to_objref(p::Ptr)
249

250
Convert a `Ptr` to an object reference. Assumes the pointer refers to a valid heap-allocated
251
Julia object. If this is not the case, undefined behavior results, hence this function is
252
considered "unsafe" and should be used with care.
253

254
See also [`pointer_from_objref`](@ref).
255
"""
256
unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Cvoid},), x)
1,040,045✔
257

258
"""
259
    pointer_from_objref(x)
260

261
Get the memory address of a Julia object as a `Ptr`. The existence of the resulting `Ptr`
262
will not protect the object from garbage collection, so you must ensure that the object
263
remains referenced for the whole time that the `Ptr` will be used.
264

265
This function may not be called on immutable objects, since they do not have
266
stable memory addresses.
267

268
See also [`unsafe_pointer_to_objref`](@ref).
269
"""
270
function pointer_from_objref(@nospecialize(x))
19,173,620✔
271
    @inline
19,170,479✔
272
    ismutable(x) || error("pointer_from_objref cannot be used on immutable objects")
19,171,286✔
273
    ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
939,113,772✔
274
end
275

276
## limited pointer arithmetic & comparison ##
277

278
isequal(x::Ptr, y::Ptr) = (x === y)
1✔
279
isless(x::Ptr{T}, y::Ptr{T}) where {T} = x < y
1✔
280

281
==(x::Ptr, y::Ptr) = UInt(x) == UInt(y)
637,785,949✔
282
<(x::Ptr,  y::Ptr) = UInt(x) < UInt(y)
56,443,066✔
283
-(x::Ptr,  y::Ptr) = UInt(x) - UInt(y)
3,976,809✔
284

285
+(x::Ptr, y::Integer) = oftype(x, add_ptr(UInt(x), (y % UInt) % UInt))
1,074,914,129✔
286
-(x::Ptr, y::Integer) = oftype(x, sub_ptr(UInt(x), (y % UInt) % UInt))
371,573,721✔
287
+(x::Integer, y::Ptr) = y + x
1✔
288

289
unsigned(x::Ptr) = UInt(x)
×
290
signed(x::Ptr) = Int(x)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc