-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More thorough aliasing detection in nonscalar copy, broadcast and assignment #25890
Changes from 14 commits
f24bc59
1e8ac8f
901514b
534bf91
0fde137
fa809cb
eeebbe7
2254dc5
d97d0c3
5410652
c451ecc
dd1588e
e16c03e
2ba5688
636453d
5caac48
1ffc135
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1047,6 +1047,86 @@ function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) whe | |
r | ||
end | ||
|
||
""" | ||
parent(A) | ||
|
||
Returns the "parent array" of an array view type (e.g., `SubArray`), or the array itself if | ||
it is not a view. | ||
|
||
# Examples | ||
```jldoctest | ||
julia> A = [1 2; 3 4] | ||
2×2 Array{Int64,2}: | ||
1 2 | ||
3 4 | ||
|
||
julia> V = view(A, 1:2, :) | ||
2×2 view(::Array{Int64,2}, 1:2, :) with eltype Int64: | ||
1 2 | ||
3 4 | ||
|
||
julia> parent(V) | ||
2×2 Array{Int64,2}: | ||
1 2 | ||
3 4 | ||
``` | ||
""" | ||
parent(a::AbstractArray) = a | ||
|
||
## rudimentary aliasing detection ## | ||
""" | ||
unalias(dest, A) | ||
|
||
Return either `A` or a copy of `A`, in a rough effort to prevent modifications to `dest` from | ||
affecting the returned object. No guarantees are provided, and each custom array must | ||
opt-into aliasing detection by overloading this method by specializing on the second argument. | ||
|
||
This function must return an object of exactly the same type as `A` for performance and type stability. | ||
|
||
See also [`mightalias`](@ref) and [`dataids`](@ref). | ||
""" | ||
unalias(dest, A) = mightalias(dest, A) ? copypreservingtype(A) : A | ||
|
||
copypreservingtype(A::Array) = copy(A) | ||
copypreservingtype(A::AbstractArray) = (@_noinline_meta; deepcopy(A)::typeof(A)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, you're right, I didn't consider how this would change the identities of the values that get assigned into the array. Perhaps we should just fall back to |
||
copypreservingtype(A) = A | ||
|
||
""" | ||
mightalias(A::AbstractArray, B::AbstractArray) | ||
|
||
Perform a conservative and rudimentary test to check if arrays `A` and `B` might share the same memory. | ||
|
||
By default, this simply checks if either of the arrays reference the same memory | ||
regions, as identified by their [`dataids`](@ref). | ||
""" | ||
mightalias(A::AbstractArray, B::AbstractArray) = !_isdisjoint(dataids(A), dataids(B)) | ||
mightalias(x, y) = false | ||
|
||
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true | ||
_isdisjoint(as::Tuple{}, bs::Tuple{Any}) = true | ||
_isdisjoint(as::Tuple{}, bs::Tuple) = true | ||
_isdisjoint(as::Tuple{Any}, bs::Tuple{}) = true | ||
_isdisjoint(as::Tuple{Any}, bs::Tuple{Any}) = as[1] != bs[1] | ||
_isdisjoint(as::Tuple{Any}, bs::Tuple) = !(as[1] in bs) | ||
_isdisjoint(as::Tuple, bs::Tuple{}) = true | ||
_isdisjoint(as::Tuple, bs::Tuple{Any}) = !(bs[1] in as) | ||
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs) | ||
|
||
""" | ||
dataids(A::AbstractArray) | ||
|
||
Return a tuple of `UInt`s that represent the mutable data segments of an array. | ||
|
||
Custom arrays that would like to opt-in to aliasing detection of their component | ||
parts can specialize this method to return the concatenation of the `dataids` of | ||
their component parts. A typical definition for an array that wraps a parent is | ||
`dataids(C::CustomArray) = dataids(C.parent)`. | ||
""" | ||
dataids(A::AbstractArray) = (UInt(objectid(A)),) | ||
dataids(A::Array) = (UInt(pointer(A)),) | ||
dataids(::AbstractRange) = () | ||
dataids(x) = () | ||
|
||
## get (getindex with a default value) ## | ||
|
||
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}}, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds like "copy-preserving type" and too similar to
eltype()
,keytype()
etc.Maybe something along
sametypecopy()
/keeptypecopy()
/unaliasingcopy()
(my fav)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point. I also like
unaliasingcopy
for now — it's likely that we'll try to separate the two meanings of copy in the future. By naming this more narrowly it gives us space for that design process.